Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bdb/bdb_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2080,6 +2080,7 @@ int bdb_get_myseqnum(bdb_state_type *bdb_state, seqnum_type *seqnum);

void bdb_replace_handle(bdb_state_type *parent, int ix, bdb_state_type *handle);

int bdb_reset_lock_counters(bdb_state_type *bdb_state);
int bdb_get_lock_counters(bdb_state_type *bdb_state, int64_t *deadlocks,
int64_t *deadlock_locks, int64_t *waits,
int64_t *requests);
Expand Down
8 changes: 8 additions & 0 deletions bdb/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ int bdb_get_lock_counters(bdb_state_type *bdb_state, int64_t *deadlocks,
return 0;
}

int bdb_reset_lock_counters(bdb_state_type *bdb_state)
{
DB_LOCK_STAT *lock_stats = NULL;
int rc = bdb_state->dbenv->lock_stat(bdb_state->dbenv, &lock_stats, DB_STAT_CLEAR);
free(lock_stats);
return rc;
}

int bdb_get_bpool_counters(bdb_state_type *bdb_state, int64_t *bpool_hits,
int64_t *bpool_misses, int64_t *rw_evicts)
{
Expand Down
3 changes: 3 additions & 0 deletions berkdb/lock/lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ static const char revid[] = "$Id: lock.c,v 11.134 2003/11/18 21:30:38 ubell Exp



__thread int64_t bdb_thr_lockreqs = 0;

extern int verbose_deadlocks;
extern int gbl_rowlocks;
extern int gbl_page_latches;
Expand Down Expand Up @@ -2241,6 +2243,7 @@ __lock_get_internal_int(lt, locker, in_locker, flags, obj, lock_mode, timeout,
}

region->stat.st_nrequests++;
bdb_thr_lockreqs++;

sh_locker = *in_locker;

Expand Down
7 changes: 7 additions & 0 deletions db/comdb2.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,13 @@ int gbl_requeue_on_tran_dispatch = 1;
int gbl_crc32c = 1;
int gbl_repscore = 0;
int gbl_surprise = 1; // TODO: change name to something else
int gbl_partition_unique = 0;
int gbl_partition_unique_debug = 0;
int gbl_partition_unique_skip_locks = 0;
long long gbl_lockreqs_deadlocked = 0;
long long gbl_lockreqs_in_pdt = 0;
long long gbl_dka_calls = 0;
long long gbl_cross_shard_calls = 0;
int gbl_check_wrong_db = 1;
int gbl_broken_max_rec_sz = 0;
int gbl_private_blkseq = 1;
Expand Down
10 changes: 10 additions & 0 deletions db/comdb2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,12 @@ struct ireq {
char debug_buf[256];
char tzname[DB_MAX_TZNAMEDB];

/* shard dbtables for cross-shard unique check (TRUNCATE partitions).
* Lives in region 2 (not zeroed by init_ireq_legacy's region3 bzero).
* Set by OSQL_PARTITION_SHARDS handler; freed at transaction end. */
struct dbtable **partition_shards;
int npartition_shards;

/************/
/* REGION 3 */
/************/
Expand Down Expand Up @@ -1432,6 +1438,7 @@ struct ireq {
uint8_t **idxInsert;
uint8_t **idxDelete;


/* osql prefault step index */
int *osql_step_ix;

Expand Down Expand Up @@ -3549,6 +3556,9 @@ extern int gbl_repscore;
extern int gbl_max_verify_retries;

extern int gbl_surprise;
extern int gbl_partition_unique;
extern int gbl_partition_unique_debug;
extern int gbl_partition_unique_skip_locks;

extern int gbl_check_wrong_db;

Expand Down
40 changes: 33 additions & 7 deletions db/constraints.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "cdb2_constants.h"
#include "comdb2.h"
#include "comdb2_atomic.h"
#include <schemachange.h>
#include "tag.h"
#include "tohex.h"
Expand Down Expand Up @@ -243,6 +244,14 @@ static inline void free_cached_delayed_indexes(struct ireq *iq)
free(iq->idxDelete);
iq->idxInsert = iq->idxDelete = NULL;
}
/* partition_shards must survive the entire transaction */
if (gbl_partition_unique_debug && gbl_partition_unique) {
if (!iq->partition_shards) {
static __thread int free_nil_count = 0;
if (++free_nil_count <= 5)
logmsg(LOGMSG_USER, "free_cached_delayed_indexes: partition_shards already NULL! iq=%p\n", (void *)iq);
}
}
}

enum ct_etype { CTE_ADD = 1, CTE_DEL, CTE_UPD };
Expand Down Expand Up @@ -1171,6 +1180,10 @@ int upsert_collision_should_force_verify_error(int flags, int ixnum)
int delayed_key_adds(struct ireq *iq, void *trans, int *blkpos, int *ixout,
int *errout)
{
if (gbl_partition_unique_debug) {
extern long long gbl_dka_calls;
ATOMIC_ADD64(gbl_dka_calls, 1);
}
int rc = 0, fndlen = 0, err = 0, limit = 0, dup_txn_insert = 0;
int idx = 0, ixkeylen = -1;
void *od_dta = NULL;
Expand Down Expand Up @@ -1408,9 +1421,26 @@ int delayed_key_adds(struct ireq *iq, void *trans, int *blkpos, int *ixout,
/* light the prefault kill bit for this subop - newkeys */
prefault_kill_bits(iq, doidx, PFRQ_NEWKEY);

/* cross-shard unique check for TRUNCATE partitions */
if (gbl_partition_unique_debug) {
static __thread int dka_count = 0;
if (++dka_count <= 3)
logmsg(LOGMSG_USER, "delayed_key_adds: iq=%p partition_shards=%p nshards=%d skip_locks=%d\n",
(void *)iq, (void *)iq->partition_shards, iq->npartition_shards,
gbl_partition_unique_skip_locks);
}
rc = check_cross_shard_unique(iq, trans, doidx, key, ixkeylen, errout);
if (rc == RC_INTERNAL_RETRY) {
*blkpos = curop->blkpos;
close_constraint_table_cursor(cur);
free_cached_delayed_indexes(iq);
ERR(rc, "deadlock", 0);
}

/* add the key */
rc = ix_addk(iq, trans, key, doidx, genid, addrrn, od_dta_tail,
od_tail_len, ix_isnullk(iq->usedb, key, doidx));
if (!rc)
rc = ix_addk(iq, trans, key, doidx, genid, addrrn, od_dta_tail, od_tail_len,
ix_isnullk(iq->usedb, key, doidx));

if (iq->vfy_idx_track) {
dup_txn_insert = track_record_index(iq, doidx, key, ixkeylen);
Expand All @@ -1431,11 +1461,7 @@ int delayed_key_adds(struct ireq *iq, void *trans, int *blkpos, int *ixout,
*errout = OP_FAILED_VERIFY;
rc = ERR_VERIFY;
} else {
reqerrstr(iq, COMDB2_CSTRT_RC_DUP,
"add key constraint duplicate key '%s' on table "
"'%s' index %d",
get_keynm_from_db_idx(iq->usedb, doidx),
iq->usedb->tablename, doidx);
reqerrstr_dup_key(iq, iq->usedb, doidx);
*errout = OP_FAILED_UNIQ;
}

Expand Down
21 changes: 21 additions & 0 deletions db/db_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ struct comdb2_metrics_store {
int64_t locks_aborted;
int64_t fstraps;
int64_t lockrequests;
int64_t lockreqs_deadlocked;
int64_t lockreqs_in_pdt;
int64_t dka_calls;
int64_t cross_shard_calls;
int64_t lockwaits;
int64_t lock_wait_time_us;
int64_t memory_ulimit;
Expand Down Expand Up @@ -202,6 +206,14 @@ comdb2_metric gbl_metrics[] = {
&stats.ismaster, NULL},
{"lockrequests", "Total lock requests", STATISTIC_INTEGER, STATISTIC_COLLECTION_TYPE_CUMULATIVE,
&stats.lockrequests, NULL},
{"lockreqs_deadlocked", "Lock requests from deadlocked transaction attempts (requires partition_unique_debug)",
STATISTIC_INTEGER, STATISTIC_COLLECTION_TYPE_CUMULATIVE, &stats.lockreqs_deadlocked, NULL},
{"lockreqs_in_pdt", "Lock requests from cross-shard unique checks (requires partition_unique_debug)",
STATISTIC_INTEGER, STATISTIC_COLLECTION_TYPE_CUMULATIVE, &stats.lockreqs_in_pdt, NULL},
{"dka_calls", "Deferred key add invocations (requires partition_unique_debug)", STATISTIC_INTEGER,
STATISTIC_COLLECTION_TYPE_CUMULATIVE, &stats.dka_calls, NULL},
{"cross_shard_calls", "Cross-shard unique index checks (requires partition_unique_debug)", STATISTIC_INTEGER,
STATISTIC_COLLECTION_TYPE_CUMULATIVE, &stats.cross_shard_calls, NULL},
{"lockwaits", "Number of lock waits", STATISTIC_INTEGER, STATISTIC_COLLECTION_TYPE_CUMULATIVE, &stats.lockwaits,
NULL},
{"lockwait_time", "Time spent in lock waits (us)", STATISTIC_INTEGER, STATISTIC_COLLECTION_TYPE_CUMULATIVE,
Expand Down Expand Up @@ -575,6 +587,15 @@ int refresh_metrics(void)
stats.sql_ssl_count = gbl_nnewsql_ssl;
stats.current_connections = net_get_num_current_non_appsock_accepts(thedb->handle_sibling) + active_appsock_conns;

extern long long gbl_lockreqs_deadlocked;
extern long long gbl_lockreqs_in_pdt;
extern long long gbl_dka_calls;
extern long long gbl_cross_shard_calls;
stats.lockreqs_deadlocked = gbl_lockreqs_deadlocked;
stats.lockreqs_in_pdt = gbl_lockreqs_in_pdt;
stats.dka_calls = gbl_dka_calls;
stats.cross_shard_calls = gbl_cross_shard_calls;

rc = bdb_get_lock_counters(thedb->bdb_env, &stats.deadlocks,
&stats.locks_aborted, &stats.lockwaits,
&stats.lockrequests);
Expand Down
13 changes: 13 additions & 0 deletions db/db_tunables.h
Original file line number Diff line number Diff line change
Expand Up @@ -2573,6 +2573,19 @@ REGISTER_TUNABLE("transaction_grace_period",
"Time to wait for connections with pending transactions to go away on exit. (Default: 60)",
TUNABLE_INTEGER, &gbl_transaction_grace_period, 0, NULL, NULL, NULL, NULL);

REGISTER_TUNABLE("partition_unique",
"Enforce unique index constraints across all shards of a TRUNCATE time partition (Default: off). "
"Does not validate pre-existing data; cross-shard duplicates present before enabling this tunable "
"are the user's responsibility to detect and resolve.",
TUNABLE_BOOLEAN, &gbl_partition_unique, NOARG, NULL, NULL, NULL, NULL);
REGISTER_TUNABLE("partition_unique_debug",
"Enable debug tracing for partition_unique cross-shard unique enforcement (Default: off). "
"Logs packet build/send on replicant, receive/store and free on master, and each cross-shard check.",
TUNABLE_BOOLEAN, &gbl_partition_unique_debug, NOARG, NULL, NULL, NULL, NULL);
REGISTER_TUNABLE("partition_unique_skip_locks",
"Debug: when set, OSQL_PARTITION_SHARDS will not acquire read table locks for sibling shards "
"(Default: off)",
TUNABLE_BOOLEAN, &gbl_partition_unique_skip_locks, NOARG, NULL, NULL, NULL, NULL);
REGISTER_TUNABLE("partition_sc_reorder", "If the schema change is serialized for a partition, run current shard last",
TUNABLE_BOOLEAN, &gbl_partition_sc_reorder, 0, NULL, NULL, NULL, NULL);
REGISTER_TUNABLE("partition_retroactively",
Expand Down
7 changes: 7 additions & 0 deletions db/handle_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,13 @@ static int init_ireq_legacy(struct dbenv *dbenv, struct ireq *iq, COMDB2BUF *sb,
iq->debug_buf[0] = '\0';
iq->tzname[0] = '\0';

/* partition_shards lives in region 2 and must be explicitly initialized */
if (gbl_partition_unique_debug && iq->partition_shards)
logmsg(LOGMSG_USER, "%s: [master] freeing partition_shards nshards=%d\n", __func__, iq->npartition_shards);
free(iq->partition_shards);
iq->partition_shards = NULL;
iq->npartition_shards = 0;

iq->where = "setup";
iq->frommach = frommach ? intern(frommach) : NULL;
iq->frompid = frompid;
Expand Down
Loading
Loading