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
16 changes: 14 additions & 2 deletions bdb/bdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,15 +705,27 @@ void bdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen,
bb_berkdb_fingerprint_rtstats_set(fingerprint, fplen, has_main_entry);
}

void bdb_fingerprint_rtstats_set_write(const unsigned char *fingerprint, size_t fplen, int has_main_entry)
{
bb_berkdb_fingerprint_rtstats_set_write(fingerprint, fplen, has_main_entry);
}

void bdb_fingerprint_rtstats_clear(void)
{
bb_berkdb_fingerprint_rtstats_clear();
}

int bdb_fingerprint_rtstats_get(const unsigned char *fingerprint, size_t fplen, uint64_t *n_pagein_read,
uint64_t *n_pagein_read_io)
uint64_t *n_pagein_read_io, uint64_t *n_write_pagein_read,
uint64_t *n_write_pagein_read_io)
{
return bb_berkdb_fingerprint_rtstats_get(fingerprint, fplen, n_pagein_read, n_pagein_read_io, n_write_pagein_read,
n_write_pagein_read_io);
}

void bdb_fingerprint_rtstats_foreach(bdb_fingerprint_rtstats_enum_fn fn, void *arg)
{
return bb_berkdb_fingerprint_rtstats_get(fingerprint, fplen, n_pagein_read, n_pagein_read_io);
bb_berkdb_fingerprint_rtstats_foreach((bb_berkdb_fingerprint_rtstats_enum_fn)fn, arg);
}

/* Call this any time to get process wide stats (which get updated locklessly)
Expand Down
8 changes: 7 additions & 1 deletion bdb/bdb_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1373,9 +1373,15 @@ const struct berkdb_thread_stats *bdb_get_thread_stats(void);
const struct berkdb_thread_stats *bdb_get_process_stats(void);

void bdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen, int has_main_entry);
void bdb_fingerprint_rtstats_set_write(const unsigned char *fingerprint, size_t fplen, int has_main_entry);
void bdb_fingerprint_rtstats_clear(void);
int bdb_fingerprint_rtstats_get(const unsigned char *fingerprint, size_t fplen, uint64_t *n_pagein_read,
uint64_t *n_pagein_read_io);
uint64_t *n_pagein_read_io, uint64_t *n_write_pagein_read,
uint64_t *n_write_pagein_read_io);
/* counts[4] = {n_pagein_read, n_pagein_read_io, n_write_pagein_read, n_write_pagein_read_io} */
typedef void (*bdb_fingerprint_rtstats_enum_fn)(const unsigned char *fingerprint, const uint64_t *counts,
int has_main_entry, void *arg);
void bdb_fingerprint_rtstats_foreach(bdb_fingerprint_rtstats_enum_fn fn, void *arg);

/* Format and print the thread stats. printfn() is a function which accepts
* a line to print (\n\0 terminated) and a context pointer. Its return value
Expand Down
8 changes: 7 additions & 1 deletion berkdb/build/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -3130,10 +3130,16 @@ void bb_berkdb_thread_stats_reset(void);

void bb_berkdb_fingerprint_rtstats_init(void);
void bb_berkdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen, int has_main_entry);
void bb_berkdb_fingerprint_rtstats_set_write(const unsigned char *fingerprint, size_t fplen, int has_main_entry);
void bb_berkdb_fingerprint_rtstats_clear(void);
void bb_berkdb_fingerprint_rtstats_bump_pagein(int did_io);
int bb_berkdb_fingerprint_rtstats_get(const unsigned char *fingerprint, size_t fplen,
uint64_t *n_pagein_read, uint64_t *n_pagein_read_io);
uint64_t *n_pagein_read, uint64_t *n_pagein_read_io,
uint64_t *n_write_pagein_read, uint64_t *n_write_pagein_read_io);
/* counts[4] = {n_pagein_read, n_pagein_read_io, n_write_pagein_read, n_write_pagein_read_io} */
typedef void (*bb_berkdb_fingerprint_rtstats_enum_fn)(const unsigned char *fingerprint,
const uint64_t *counts, int has_main_entry, void *arg);
void bb_berkdb_fingerprint_rtstats_foreach(bb_berkdb_fingerprint_rtstats_enum_fn fn, void *arg);

extern int gbl_bb_berkdb_enable_thread_stats;
extern int gbl_bb_berkdb_enable_lock_timing;
Expand Down
127 changes: 109 additions & 18 deletions berkdb/mp/mp_fingerprint_rtstats.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@ struct fingerprint_rtstats {
unsigned char fingerprint[FP_RTSTATS_KEYSZ]; /* hash key, must be first */
uint64_t n_pagein_read; /* every successful __memp_fget_internal()
* return attributed to this fingerprint
* (cache hit or miss) */
* during SQL read execution (cache hit or
* miss) */
uint64_t n_pagein_read_io; /* subset of n_pagein_read where the fetch
* required an actual disk read */
uint64_t n_write_pagein_read; /* same as n_pagein_read, but for page-ins
* generated while the master applies a write
* schedule for this fingerprint */
uint64_t n_write_pagein_read_io; /* subset of n_write_pagein_read that
* required an actual disk read */
int has_main_entry; /* 1 if gbl_fingerprint_hash already had an
* entry for this fingerprint when this
* stat entry was created (set once, at
* creation time, not refreshed). Lets a
* future write-side commit distinguish
* "this machine has full query info" from
* "we only know the fingerprint + counts".
* Unused by read-side logic. */
* entry for this fingerprint when this stat
* entry was created (set once at creation,
* never refreshed). Diagnostic only: the
* comdb2_fingerprints systable derives its
* has_query_info column from live
* gbl_fingerprint_hash membership, not from
* this (possibly stale) flag. */
};

static hash_t *gbl_fingerprint_rtstats_hash;
Expand All @@ -63,12 +69,21 @@ int gbl_fingerprint_rtstats_max_entries = 5000;
static struct fingerprint_rtstats gbl_fingerprint_rtstats_nofingerprint;

static pthread_key_t fingerprint_rtstats_key;
/*
* Per-thread mode flag paired with fingerprint_rtstats_key. NULL (the default)
* means the armed thread is doing SQL read execution; non-NULL means it is a
* master block-processor thread applying a write schedule. bump_pagein() reads
* it to decide which pair of counters to increment. Must be per-thread (not on
* the shared entry) because many threads share one fingerprint entry.
*/
static pthread_key_t fingerprint_rtstats_write_key;
static int fingerprint_rtstats_inited = 0;

void
bb_berkdb_fingerprint_rtstats_init(void)
{
Pthread_key_create(&fingerprint_rtstats_key, NULL);
Pthread_key_create(&fingerprint_rtstats_write_key, NULL);

Pthread_mutex_lock(&gbl_fingerprint_rtstats_hash_mu);
if (gbl_fingerprint_rtstats_hash == NULL)
Expand All @@ -79,18 +94,22 @@ bb_berkdb_fingerprint_rtstats_init(void)
}

/*
* Called once per statement, as soon as its fingerprint is known and
* before cursor traversal begins. Finds-or-creates the stat entry for
* this fingerprint and points the calling thread's TLS slot at it.
* Find-or-create the stat entry for this fingerprint and point the calling
* thread's TLS slot at it, recording whether the thread is in write-apply mode.
* Shared by the read-side set (is_write=0) and the master write-side set
* (is_write=1).
*/
void
bb_berkdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen, int has_main_entry)
static void
fingerprint_rtstats_set_internal(const unsigned char *fingerprint, size_t fplen,
int has_main_entry, int is_write)
{
struct fingerprint_rtstats *t;

if (!fingerprint_rtstats_inited || fingerprint == NULL || fplen != FP_RTSTATS_KEYSZ)
return;

Pthread_setspecific(fingerprint_rtstats_write_key, is_write ? (void *)1 : NULL);

Pthread_mutex_lock(&gbl_fingerprint_rtstats_hash_mu);
if (gbl_fingerprint_rtstats_hash == NULL)
gbl_fingerprint_rtstats_hash = hash_init(FP_RTSTATS_KEYSZ);
Expand Down Expand Up @@ -125,13 +144,37 @@ bb_berkdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen
Pthread_setspecific(fingerprint_rtstats_key, t);
}

/*
* Called once per statement, as soon as its fingerprint is known and
* before cursor traversal begins. Finds-or-creates the stat entry for
* this fingerprint and points the calling thread's TLS slot at it.
*/
void
bb_berkdb_fingerprint_rtstats_set(const unsigned char *fingerprint, size_t fplen, int has_main_entry)
{
fingerprint_rtstats_set_internal(fingerprint, fplen, has_main_entry, 0);
}

/*
* Master write-side arm. Called on the block-processor thread when it receives
* an OSQL_FINGERPRINT op, before it applies the write ops that follow. Page-ins
* generated until the next clear are attributed to this fingerprint's write
* counters.
*/
void
bb_berkdb_fingerprint_rtstats_set_write(const unsigned char *fingerprint, size_t fplen, int has_main_entry)
{
fingerprint_rtstats_set_internal(fingerprint, fplen, has_main_entry, 1);
}

/* Called when the statement is done (or on error paths). */
void
bb_berkdb_fingerprint_rtstats_clear(void)
{
if (!fingerprint_rtstats_inited)
return;
Pthread_setspecific(fingerprint_rtstats_key, NULL);
Pthread_setspecific(fingerprint_rtstats_write_key, NULL);
}

/*
Expand All @@ -145,15 +188,24 @@ void
bb_berkdb_fingerprint_rtstats_bump_pagein(int did_io)
{
struct fingerprint_rtstats *t = NULL;
int is_write = 0;

if (fingerprint_rtstats_inited)
if (fingerprint_rtstats_inited) {
t = pthread_getspecific(fingerprint_rtstats_key);
is_write = pthread_getspecific(fingerprint_rtstats_write_key) != NULL;
}
if (t == NULL)
t = &gbl_fingerprint_rtstats_nofingerprint;

ATOMIC_ADD64(t->n_pagein_read, 1);
if (did_io)
ATOMIC_ADD64(t->n_pagein_read_io, 1);
if (is_write) {
ATOMIC_ADD64(t->n_write_pagein_read, 1);
if (did_io)
ATOMIC_ADD64(t->n_write_pagein_read_io, 1);
} else {
ATOMIC_ADD64(t->n_pagein_read, 1);
if (did_io)
ATOMIC_ADD64(t->n_pagein_read_io, 1);
}
}

/*
Expand All @@ -165,13 +217,16 @@ bb_berkdb_fingerprint_rtstats_bump_pagein(int did_io)
*/
int
bb_berkdb_fingerprint_rtstats_get(const unsigned char *fingerprint, size_t fplen,
uint64_t *n_pagein_read, uint64_t *n_pagein_read_io)
uint64_t *n_pagein_read, uint64_t *n_pagein_read_io,
uint64_t *n_write_pagein_read, uint64_t *n_write_pagein_read_io)
{
struct fingerprint_rtstats *t;
int found = 0;

*n_pagein_read = 0;
*n_pagein_read_io = 0;
*n_write_pagein_read = 0;
*n_write_pagein_read_io = 0;

if (!fingerprint_rtstats_inited || fingerprint == NULL || fplen != FP_RTSTATS_KEYSZ)
return 0;
Expand All @@ -184,10 +239,46 @@ bb_berkdb_fingerprint_rtstats_get(const unsigned char *fingerprint, size_t fplen
* ATOMIC_ADD64, so load them atomically too. */
*n_pagein_read = ATOMIC_LOAD64(t->n_pagein_read);
*n_pagein_read_io = ATOMIC_LOAD64(t->n_pagein_read_io);
*n_write_pagein_read = ATOMIC_LOAD64(t->n_write_pagein_read);
*n_write_pagein_read_io = ATOMIC_LOAD64(t->n_write_pagein_read_io);
found = 1;
}
}
Pthread_mutex_unlock(&gbl_fingerprint_rtstats_hash_mu);

return found;
}

/*
* Enumerate every rtstats entry for reporting (the comdb2_fingerprints
* systable). Invokes fn once per entry under the hash mutex; the callback
* must not call back into this subsystem (it would deadlock) and must not
* block. Counters are passed as counts[4] = {n_pagein_read, n_pagein_read_io,
* n_write_pagein_read, n_write_pagein_read_io} so no struct type needs to be
* shared across the bdb/berkdb boundary.
*/
void
bb_berkdb_fingerprint_rtstats_foreach(bb_berkdb_fingerprint_rtstats_enum_fn fn, void *arg)
{
struct fingerprint_rtstats *t;
void *hash_cur;
unsigned int hash_cur_buk;

if (!fingerprint_rtstats_inited || fn == NULL)
return;

Pthread_mutex_lock(&gbl_fingerprint_rtstats_hash_mu);
if (gbl_fingerprint_rtstats_hash != NULL) {
t = hash_first(gbl_fingerprint_rtstats_hash, &hash_cur, &hash_cur_buk);
while (t != NULL) {
uint64_t counts[4];
counts[0] = ATOMIC_LOAD64(t->n_pagein_read);
counts[1] = ATOMIC_LOAD64(t->n_pagein_read_io);
counts[2] = ATOMIC_LOAD64(t->n_write_pagein_read);
counts[3] = ATOMIC_LOAD64(t->n_write_pagein_read_io);
fn(t->fingerprint, counts, t->has_main_entry, arg);
t = hash_next(gbl_fingerprint_rtstats_hash, &hash_cur, &hash_cur_buk);
}
}
Pthread_mutex_unlock(&gbl_fingerprint_rtstats_hash_mu);
}
27 changes: 27 additions & 0 deletions db/db_fingerprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,33 @@ int clear_fingerprints(int *plans_count)
return count;
}

/*
* Returns 1 if gbl_fingerprint_hash already has an entry for this fingerprint
* (i.e. this node has the full normalized-SQL / query info), 0 otherwise. Used
* by the master write-side arm to record has_main_entry.
*/
int fingerprint_has_main_entry(const unsigned char fingerprint[FINGERPRINTSZ])
{
int found = 0;
Pthread_mutex_lock(&gbl_fingerprint_hash_mu);
if (gbl_fingerprint_hash != NULL && hash_find(gbl_fingerprint_hash, fingerprint) != NULL)
found = 1;
Pthread_mutex_unlock(&gbl_fingerprint_hash_mu);
return found;
}

/*
* Returns 1 if the fingerprint is all-zeros -- calc_fingerprint() produces this
* for a statement with no normalized SQL. There is nothing useful to attribute
* to such a fingerprint, so the write-side send paths skip it rather than pool
* unrelated traffic under a single all-zero key.
*/
int fingerprint_is_zero(const unsigned char fingerprint[FINGERPRINTSZ])
{
static const unsigned char zero[FINGERPRINTSZ] = {0};
return memcmp(fingerprint, zero, FINGERPRINTSZ) == 0;
}

void calc_fingerprint(const char *zNormSql, size_t *pnNormSql,
unsigned char fingerprint[FINGERPRINTSZ]) {
memset(fingerprint, 0, FINGERPRINTSZ);
Expand Down
1 change: 1 addition & 0 deletions db/db_tunables.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ extern uint32_t gbl_rand_elect_min_ms;
extern int gbl_rand_elect_max_ms;
extern int gbl_handle_buf_add_latency_ms;
extern int gbl_osql_send_startgen;
extern int gbl_osql_send_fingerprint;
extern int gbl_create_default_user;
extern int gbl_allow_neg_column_size;
extern int gbl_client_heartbeat_ms;
Expand Down
6 changes: 6 additions & 0 deletions db/db_tunables.h
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,12 @@ REGISTER_TUNABLE("osql_send_startgen",
TUNABLE_BOOLEAN, &gbl_osql_send_startgen,
EXPERIMENTAL | INTERNAL, NULL, NULL, NULL, NULL);

REGISTER_TUNABLE("osql_send_fingerprint",
"Send SQL fingerprint in the osql stream so the master can "
"attribute write-apply page-in I/O to it. Keep off until the "
"whole cluster is upgraded. (Default: off)",
TUNABLE_BOOLEAN, &gbl_osql_send_fingerprint, EXPERIMENTAL | INTERNAL, NULL, NULL, NULL, NULL);

REGISTER_TUNABLE("client_heartbeat_ms",
"Number of milliseconds between client api heartbeats. "
"(Default: 100)",
Expand Down
5 changes: 5 additions & 0 deletions db/osqlblockproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,11 @@ static int apply_changes(struct ireq *iq, blocksql_tran_t *tran, void *iq_tran,
out_rc = process_this_session(iq, iq_tran, iq->sorese, &bdberr, nops, err,
dbc, dbc_ins, func);

/* An OSQL_FINGERPRINT op may have armed this (pooled) block-processor
* thread's write-side fingerprint TLS while applying the session above;
* clear it so page-ins from unrelated later work aren't misattributed. */
bdb_fingerprint_rtstats_clear();

Pthread_mutex_unlock(&tran->store_mtx);

/* close the cursor */
Expand Down
Loading
Loading