diff --git a/db/comdb2.h b/db/comdb2.h index 075da5a144..396b16d151 100644 --- a/db/comdb2.h +++ b/db/comdb2.h @@ -1419,8 +1419,9 @@ struct ireq { /* List of indices that we've written to detect uncommittable upsert txns */ hash_t *vfy_idx_hash; - int dup_key_insert; + /* Whether this txn has ignored upsert conflicts */ + int upsert_ignored; /* List of genids that we've written to detect uncommittable txn's */ hash_t *vfy_genid_hash; diff --git a/db/constraints.c b/db/constraints.c index 1a628bedc4..421005fb8f 100644 --- a/db/constraints.c +++ b/db/constraints.c @@ -1162,10 +1162,10 @@ int upsert_collision_should_force_verify_error(int flags, int ixnum) - If the client did 'insert ... on conflict ...', then upsert_idx will specify the index passed in the on conflict clause - If the client did 'replace into ...', then upsert_idx will be - MAXINDEX + 1 + MAXINDEX + 1 (UPSERT_CONFLICT_ALL_INDEXES) */ const int upsert_idx = flags >> 8; - return upsert_idx == ixnum || upsert_idx == MAXINDEX + 1; + return upsert_idx == ixnum || upsert_idx == UPSERT_CONFLICT_ALL_INDEXES; } int delayed_key_adds(struct ireq *iq, void *trans, int *blkpos, int *ixout, diff --git a/db/handle_buf.c b/db/handle_buf.c index 6471406773..a568aaef0a 100644 --- a/db/handle_buf.c +++ b/db/handle_buf.c @@ -639,6 +639,7 @@ void *thd_req(void *vthd) } thd->iq->vfy_idx_track = 0; thd->iq->dup_key_insert = 0; + thd->iq->upsert_ignored = 0; #if 0 fprintf(stderr, "%s:%d: THD=%p relablk iq=%p\n", __func__, __LINE__, pthread_self(), thd->iq); #endif diff --git a/db/indices.c b/db/indices.c index 6332f3dca9..6c127d5ea4 100644 --- a/db/indices.c +++ b/db/indices.c @@ -264,6 +264,21 @@ int track_record_index(struct ireq *iq, int ixnum, void *key, int ixkeylen) return is_dup; } +static int check_upsert_index(struct ireq *iq, void *trans, int idx, blob_buffer_t *blobs, size_t maxblobs, + int *opfailcode, int *ixfailnum, int *retrc, void *od_dta, size_t od_len, + unsigned long long ins_keys) +{ + /* Ignore dup keys */ + if (iq->usedb->ix_dupes[idx]) { + return 0; + } + /* Check for partial keys only when needed. */ + if (gbl_partial_indexes && iq->usedb->ix_partial && !(ins_keys & (1ULL << idx))) { + return 0; + } + return check_index(iq, trans, idx, blobs, maxblobs, opfailcode, ixfailnum, retrc, od_dta, od_len, ins_keys); +} + /* If a specific index has been used in the ON CONFLICT (idx) DO NOTHING * clause (aka upsert target/index), then we must first perform check for * that particular index and bail out (ignore) if there's a similar entry @@ -277,42 +292,21 @@ int check_for_upsert(struct ireq *iq, void *trans, blob_buffer_t *blobs, size_t int upsert_idx = rec_flags >> 8; /* Perform the check for upsert index first. */ - if (upsert_idx != MAXINDEX + 1) { - - /* It must be a unique key. */ - assert(iq->usedb->ix_dupes[upsert_idx] == 0); - - /* Check for partial keys only when needed. */ - if (gbl_partial_indexes && iq->usedb->ix_partial && - !(ins_keys & (1ULL << upsert_idx))) { - /* NOOP */ - } else { - rc = check_index(iq, trans, upsert_idx, blobs, maxblobs, opfailcode, ixfailnum, retrc, od_dta, od_len, - ins_keys); - if (rc) { - return rc; - } + if (upsert_idx != UPSERT_CONFLICT_ALL_INDEXES) { + rc = check_upsert_index(iq, trans, upsert_idx, blobs, maxblobs, opfailcode, ixfailnum, retrc, od_dta, od_len, + ins_keys); + if (rc) { + return rc; } } for (int ixnum = 0; ixnum < iq->usedb->nix; ixnum++) { /* Skip check for upsert index, was already checked above. */ - if ((upsert_idx != MAXINDEX + 1) && (ixnum == upsert_idx)) { - continue; - } - - /* Ignore dup keys */ - if (iq->usedb->ix_dupes[ixnum] != 0) { + if ((upsert_idx != UPSERT_CONFLICT_ALL_INDEXES) && (ixnum == upsert_idx)) { continue; } - - /* Check for partial keys only when needed. */ - if (gbl_partial_indexes && iq->usedb->ix_partial && - !(ins_keys & (1ULL << ixnum))) { - continue; - } - - rc = check_index(iq, trans, ixnum, blobs, maxblobs, opfailcode, ixfailnum, retrc, od_dta, od_len, ins_keys); + rc = check_upsert_index(iq, trans, ixnum, blobs, maxblobs, opfailcode, ixfailnum, retrc, od_dta, od_len, + ins_keys); if (rc) { return rc; } diff --git a/db/indices.h b/db/indices.h index 08398b6a68..bb4ff3cb49 100644 --- a/db/indices.h +++ b/db/indices.h @@ -17,6 +17,9 @@ #ifndef INCLUDED_INDICES_H #define INCLUDED_INDICES_H +#include +#define UPSERT_CONFLICT_ALL_INDEXES (MAXINDEX + 1) + int track_record_index(struct ireq *iq, int ixnum, void *key, int ixkeylen); int check_for_upsert(struct ireq *iq, void *trans, blob_buffer_t *blobs, size_t maxblobs, int *opfailcode, diff --git a/db/osqlblockproc.c b/db/osqlblockproc.c index 42b7d30383..ef36858c82 100644 --- a/db/osqlblockproc.c +++ b/db/osqlblockproc.c @@ -1183,6 +1183,8 @@ static int apply_changes(struct ireq *iq, blocksql_tran_t *tran, void *iq_tran, hash_clear(iq->vfy_idx_hash); } + iq->upsert_ignored = 0; + /* create a cursor */ dbc = bdb_temp_table_cursor(thedb->bdb_env, tran->db, NULL, &bdberr); if (!dbc || bdberr) { diff --git a/db/osqlcomm.c b/db/osqlcomm.c index ae40ac5955..8410d1cc7c 100644 --- a/db/osqlcomm.c +++ b/db/osqlcomm.c @@ -57,6 +57,7 @@ #include "logical_cron.h" #include "sc_logic.h" #include "eventlog.h" +#include "indices.h" #include #define MAX_CLUSTER REPMAX @@ -7331,7 +7332,7 @@ int osql_process_packet(struct ireq *iq, uuid_t uuid, void *trans, char **pmsg, get_keynm_from_db_idx(iq->usedb, err->ixnum), iq->usedb->tablename, err->ixnum); err->errcode = ERR_UNCOMMITTABLE_TXN; - goto done_delete; + goto done_insert; } if (upsert_collision_should_force_verify_error(dt.upsert_flags, err->ixnum)) { @@ -7341,20 +7342,23 @@ int osql_process_packet(struct ireq *iq, uuid_t uuid, void *trans, char **pmsg, if ((dt.upsert_flags & OSQL_IGNORE_FAILURE) != 0) { const int upsert_idx = dt.upsert_flags >> 8; - if (upsert_idx == MAXINDEX + 1) { + if (upsert_idx == UPSERT_CONFLICT_ALL_INDEXES) { /* We're asked to ignore DUPs for all unique indices, no insert took place.*/ + iq->upsert_ignored = 1; err->errcode = 0; rc = 0; - goto done_delete; + goto done_insert; } else if ((dt.upsert_flags & OSQL_FORCE_VERIFY) == 1) { + iq->upsert_ignored = 0; err->errcode = 0; rc = 0; - goto done_delete; + goto done_insert; } else if (upsert_idx == err->ixnum) { /* We're asked to ignore DUPs for this particular * index, no insert took place.*/ + iq->upsert_ignored = 1; err->errcode = 0; rc = 0; - goto done_delete; + goto done_insert; } } @@ -7377,7 +7381,7 @@ int osql_process_packet(struct ireq *iq, uuid_t uuid, void *trans, char **pmsg, rrn, bdb_genid_to_host_order(newgenid)); if (0) { -done_delete: + done_insert: EVENTLOG_DEBUG( uuidstr_t ustr; comdb2uuidstr(uuid, ustr); diff --git a/db/toblock.c b/db/toblock.c index 14ef5bdf5b..9978fdac86 100644 --- a/db/toblock.c +++ b/db/toblock.c @@ -5079,6 +5079,10 @@ static int toblock_main_int(struct javasp_trans_state *javasp_trans_handle, stru } else { nops += tmpnops; iq->sorese->nops = nops; + if (tmpnops == 0 && iq->upsert_ignored) { + logmsg(LOGMSG_DEBUG, "upsert did not insert, skipping constraints\n"); + goto serializable_check; + } } } @@ -5230,6 +5234,7 @@ static int toblock_main_int(struct javasp_trans_state *javasp_trans_handle, stru GOTOBACKOUT; } +serializable_check: Pthread_rwlock_rdlock(&commit_lock); hascommitlock = 1; if (iq->arr || iq->selectv_arr) {