Commit ed1478ff authored by Barry Perlman's avatar Barry Perlman Committed by Yoni Fogel

[t:4283] Closes #4283 Detect begin checkpoint in critical regions.

git-svn-id: file:///svn/toku/tokudb@37926 c7de825b-a66e-492c-adef-691d508d4ae1
parent a37a3152
...@@ -169,6 +169,8 @@ struct cachetable { ...@@ -169,6 +169,8 @@ struct cachetable {
KIBBUTZ kibbutz; // another pool of worker threads and jobs to do asynchronously. KIBBUTZ kibbutz; // another pool of worker threads and jobs to do asynchronously.
LSN lsn_of_checkpoint_in_progress; LSN lsn_of_checkpoint_in_progress;
uint64_t checkpoint_sequence_number; // just a free-running sequence number, used for detecting threadsafety bugs
uint64_t checkpoint_prohibited; // nonzero when checkpoints are prohibited, used for detecting threadsafety bugs
u_int32_t checkpoint_num_files; // how many cachefiles are in the checkpoint u_int32_t checkpoint_num_files; // how many cachefiles are in the checkpoint
u_int32_t checkpoint_num_txns; // how many transactions are in the checkpoint u_int32_t checkpoint_num_txns; // how many transactions are in the checkpoint
PAIR pending_head; // list of pairs marked with checkpoint_pending PAIR pending_head; // list of pairs marked with checkpoint_pending
...@@ -196,6 +198,18 @@ struct cachetable { ...@@ -196,6 +198,18 @@ struct cachetable {
int64_t size_cachepressure; int64_t size_cachepressure;
}; };
// Code bracketed with {BEGIN_CRITICAL_REGION; ... END_CRITICAL_REGION;} macros
// are critical regions in which a checkpoint is not permitted to begin.
#define BEGIN_CRITICAL_REGION {uint64_t cp_seqnum = ct->checkpoint_sequence_number; \
__sync_fetch_and_add(&ct->checkpoint_prohibited, 1);
#define END_CRITICAL_REGION invariant(cp_seqnum == ct->checkpoint_sequence_number); \
invariant(ct->checkpoint_prohibited > 0); \
__sync_fetch_and_sub(&ct->checkpoint_prohibited, 1); }
// Lock the cachetable // Lock the cachetable
static inline void cachefiles_lock(CACHETABLE ct) { static inline void cachefiles_lock(CACHETABLE ct) {
int r = toku_pthread_mutex_lock(&ct->cachefiles_mutex); resource_assert_zero(r); int r = toku_pthread_mutex_lock(&ct->cachefiles_mutex); resource_assert_zero(r);
...@@ -1840,6 +1854,7 @@ void toku_checkpoint_pairs( ...@@ -1840,6 +1854,7 @@ void toku_checkpoint_pairs(
); );
} }
int toku_cachetable_put_with_dep_pairs( int toku_cachetable_put_with_dep_pairs(
CACHEFILE cachefile, CACHEFILE cachefile,
CACHETABLE_GET_KEY_AND_FULLHASH get_key_and_fullhash, CACHETABLE_GET_KEY_AND_FULLHASH get_key_and_fullhash,
...@@ -1879,35 +1894,41 @@ int toku_cachetable_put_with_dep_pairs( ...@@ -1879,35 +1894,41 @@ int toku_cachetable_put_with_dep_pairs(
// cachetable_put_internal does not release the cachetable lock // cachetable_put_internal does not release the cachetable lock
// //
cachetable_wait_write(ct); cachetable_wait_write(ct);
get_key_and_fullhash(key, fullhash, get_key_and_fullhash_extra); int rval;
int r = cachetable_put_internal( {
cachefile, BEGIN_CRITICAL_REGION;
*key,
*fullhash, get_key_and_fullhash(key, fullhash, get_key_and_fullhash_extra);
value, rval = cachetable_put_internal(
attr, cachefile,
flush_callback, *key,
pe_est_callback, *fullhash,
pe_callback, value,
cleaner_callback, attr,
write_extraargs flush_callback,
); pe_est_callback,
pe_callback,
// cleaner_callback,
// now that we have inserted the row, let's checkpoint the write_extraargs
// dependent nodes, if they need checkpointing );
//
checkpoint_dependent_pairs( //
ct, // now that we have inserted the row, let's checkpoint the
num_dependent_pairs, // dependent nodes, if they need checkpointing
dependent_cfs, //
dependent_keys, checkpoint_dependent_pairs(
dependent_fullhash, ct,
dependent_dirty num_dependent_pairs,
); dependent_cfs,
dependent_keys,
dependent_fullhash,
dependent_dirty
);
END_CRITICAL_REGION;
}
cachetable_unlock(ct); cachetable_unlock(ct);
return r; return rval;
} }
...@@ -2176,40 +2197,47 @@ int toku_cachetable_get_and_pin_with_dep_pairs ( ...@@ -2176,40 +2197,47 @@ int toku_cachetable_get_and_pin_with_dep_pairs (
*value = p->value; *value = p->value;
if (sizep) *sizep = p->attr.size; if (sizep) *sizep = p->attr.size;
//
// A checkpoint cannot begin while we are checking dependent pairs or pending bits. {
// Here is why. BEGIN_CRITICAL_REGION;
//
// Now that we have all of the locks on the pairs we //
// care about, we can take care of the necessary checkpointing. // A checkpoint must not begin while we are checking dependent pairs or pending bits.
// For each pair, we simply need to write the pair if it is // Here is why.
// pending a checkpoint. If no pair is pending a checkpoint, //
// then all of this work will be done with the cachetable lock held, // Now that we have all of the locks on the pairs we
// so we don't need to worry about a checkpoint beginning // care about, we can take care of the necessary checkpointing.
// in the middle of any operation below. If some pair // For each pair, we simply need to write the pair if it is
// is pending a checkpoint, then the checkpoint thread // pending a checkpoint. If no pair is pending a checkpoint,
// will not complete its current checkpoint until it can // then all of this work will be done with the cachetable lock held,
// successfully grab a lock on the pending pair and // so we don't need to worry about a checkpoint beginning
// remove it from its list of pairs pending a checkpoint. // in the middle of any operation below. If some pair
// This cannot be done until we release the lock // is pending a checkpoint, then the checkpoint thread
// that we have, which is not done in this function. // will not complete its current checkpoint until it can
// So, the point is, it is impossible for a checkpoint // successfully grab a lock on the pending pair and
// to begin while we write any of these locked pairs // remove it from its list of pairs pending a checkpoint.
// for checkpoint, even though writing a pair releases // This cannot be done until we release the lock
// the cachetable lock. // that we have, which is not done in this function.
// // So, the point is, it is impossible for a checkpoint
if (p->checkpoint_pending) { // to begin while we write any of these locked pairs
write_locked_pair_for_checkpoint(ct, p); // for checkpoint, even though writing a pair releases
} // the cachetable lock.
//
if (p->checkpoint_pending) {
write_locked_pair_for_checkpoint(ct, p);
}
checkpoint_dependent_pairs( checkpoint_dependent_pairs(
ct, ct,
num_dependent_pairs, num_dependent_pairs,
dependent_cfs, dependent_cfs,
dependent_keys, dependent_keys,
dependent_fullhash, dependent_fullhash,
dependent_dirty dependent_dirty
); );
END_CRITICAL_REGION;
}
r = maybe_flush_some(ct, 0); r = maybe_flush_some(ct, 0);
cachetable_unlock(ct); cachetable_unlock(ct);
...@@ -3111,6 +3139,8 @@ toku_cachetable_begin_checkpoint (CACHETABLE ct, TOKULOGGER logger) { ...@@ -3111,6 +3139,8 @@ toku_cachetable_begin_checkpoint (CACHETABLE ct, TOKULOGGER logger) {
assert(r==0); assert(r==0);
} }
cachetable_lock(ct); cachetable_lock(ct);
invariant(ct->checkpoint_prohibited == 0); // detect threadsafety bugs
ct->checkpoint_sequence_number++;
//Initialize accountability counters //Initialize accountability counters
ct->checkpoint_num_files = 0; ct->checkpoint_num_files = 0;
ct->checkpoint_num_txns = 0; ct->checkpoint_num_txns = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment