From 41f52703faeb569fdbdfd68c2c2451f6ceff5aed Mon Sep 17 00:00:00 2001 From: Jun Date: Thu, 29 Mar 2018 16:23:58 -0400 Subject: [PATCH] [TDB-20] With checkpoint disabled, closing FT file still rotates header. [Updated the comments and formats from the last PR.] This is an attempt based on @BohuTang's patch https://github.com/percona/PerconaFT/pull/331 in particular, the ctest mostly comes from his with minor updates. Summary: 1) The issue is real. 2) @Bohu's patch works for mediating the issue but somewhat introduces a ft leak that the ft with ref=0 may be left until next open/close or checkpoint. 3) If ft_close should be held off upon a backup, then it simply means a backup should hold a ref to the ft and responsible for closing ft up if it is the last one to hold it, like any other possible referencer. including the checkpoint, the txn and ft handlers. 4) mtr test contributed by @BohuTang still passes. (in a different PS PR). --- ft/cachetable/cachetable-internal.h | 5 + ft/cachetable/cachetable.cc | 37 +++++- ft/cachetable/cachetable.h | 6 +- ft/ft-internal.h | 4 +- ft/ft.cc | 84 +++++++----- ft/tests/cachetable-pin-checkpoint.cc | 20 +-- ft/tests/cachetable-put-checkpoint.cc | 16 +-- ft/tests/cachetable-simple-close.cc | 16 +-- ft/tests/cachetable-test.h | 16 +-- ft/tests/fifo-test.cc | 12 +- ft/tests/ft-in-backup-test.cc | 176 ++++++++++++++++++++++++++ src/ydb.cc | 10 +- 12 files changed, 317 insertions(+), 85 deletions(-) create mode 100644 ft/tests/ft-in-backup-test.cc diff --git a/ft/cachetable/cachetable-internal.h b/ft/cachetable/cachetable-internal.h index 05fb771de..3e7cf299b 100644 --- a/ft/cachetable/cachetable-internal.h +++ b/ft/cachetable/cachetable-internal.h @@ -161,6 +161,9 @@ struct cachefile { void (*end_checkpoint_userdata)(CACHEFILE cf, int fd, void *userdata); // after checkpointing cachefiles call this function. void (*note_pin_by_checkpoint)(CACHEFILE cf, void *userdata); // add a reference to the userdata to prevent it from being removed from memory void (*note_unpin_by_checkpoint)(CACHEFILE cf, void *userdata); // add a reference to the userdata to prevent it from being removed from memory + + void (*note_pin_by_backup)(CACHEFILE cf, void *userdata); // add a reference to the userdata to prevent it from being removed from memory + void (*note_unpin_by_backup)(CACHEFILE cf, void *userdata); // add a reference to the userdata to prevent it from being removed from memory BACKGROUND_JOB_MANAGER bjm; }; @@ -413,6 +416,8 @@ class checkpointer { void add_background_job(); void remove_background_job(); void end_checkpoint(void (*testcallback_f)(void*), void* testextra); + void begin_backup(); + void end_backup(); TOKULOGGER get_logger(); // used during begin_checkpoint void increment_num_txns(); diff --git a/ft/cachetable/cachetable.cc b/ft/cachetable/cachetable.cc index d97d87622..28a36ebad 100644 --- a/ft/cachetable/cachetable.cc +++ b/ft/cachetable/cachetable.cc @@ -2793,6 +2793,37 @@ void toku_cachetable_end_checkpoint(CHECKPOINTER cp, TOKULOGGER UU(logger), cp->end_checkpoint(testcallback_f, testextra); } +// in_backup begin + +struct iterate_note_pin_backup { + static int fn(const CACHEFILE &cf, uint32_t UU(idx), void **UU(extra)) { + assert(cf->note_pin_by_backup); + cf->note_pin_by_backup(cf, cf->userdata); + return 0; + } +}; + +struct iterate_note_unpin_backup { + static int fn(const CACHEFILE &cf, uint32_t UU(idx), void **UU(extra)) { + assert(cf->note_unpin_by_backup); + cf->note_unpin_by_backup(cf, cf->userdata); + return 0; + } +}; +void toku_cachetable_begin_backup(CACHETABLE ct) +{ + ct->cf_list.read_lock(); + ct->cf_list.m_active_fileid.iterate(nullptr); + ct->cf_list.read_unlock(); +} + +void toku_cachetable_end_backup(CACHETABLE ct) +{ + ct->cf_list.m_active_fileid.iterate(nullptr); +} + +// in_backup end + TOKULOGGER toku_cachefile_logger (CACHEFILE cf) { return cf->cachetable->cp.get_logger(); } @@ -2909,7 +2940,9 @@ toku_cachefile_set_userdata (CACHEFILE cf, void (*begin_checkpoint_userdata)(LSN, void*), void (*end_checkpoint_userdata)(CACHEFILE, int, void*), void (*note_pin_by_checkpoint)(CACHEFILE, void*), - void (*note_unpin_by_checkpoint)(CACHEFILE, void*)) { + void (*note_unpin_by_checkpoint)(CACHEFILE, void*), + void (*note_pin_by_backup)(CACHEFILE, void*), + void (*note_unpin_by_backup)(CACHEFILE, void*)) { cf->userdata = userdata; cf->log_fassociate_during_checkpoint = log_fassociate_during_checkpoint; cf->close_userdata = close_userdata; @@ -2919,6 +2952,8 @@ toku_cachefile_set_userdata (CACHEFILE cf, cf->end_checkpoint_userdata = end_checkpoint_userdata; cf->note_pin_by_checkpoint = note_pin_by_checkpoint; cf->note_unpin_by_checkpoint = note_unpin_by_checkpoint; + cf->note_pin_by_backup = note_pin_by_backup; + cf->note_unpin_by_backup = note_unpin_by_backup; } void *toku_cachefile_get_userdata(CACHEFILE cf) { diff --git a/ft/cachetable/cachetable.h b/ft/cachetable/cachetable.h index c5c21b49f..6f69cde85 100644 --- a/ft/cachetable/cachetable.h +++ b/ft/cachetable/cachetable.h @@ -147,6 +147,8 @@ void toku_cachetable_begin_checkpoint (CHECKPOINTER cp, struct tokulogger *logge void toku_cachetable_end_checkpoint(CHECKPOINTER cp, struct tokulogger *logger, void (*testcallback_f)(void*), void * testextra); +void toku_cachetable_begin_backup(CACHETABLE ct); +void toku_cachetable_end_backup(CACHETABLE ct); // Shuts down checkpoint thread // Requires no locks be held that are taken by the checkpoint function @@ -285,7 +287,9 @@ void toku_cachefile_set_userdata(CACHEFILE cf, void *userdata, void (*begin_checkpoint_userdata)(LSN, void*), void (*end_checkpoint_userdata)(CACHEFILE, int, void*), void (*note_pin_by_checkpoint)(CACHEFILE, void*), - void (*note_unpin_by_checkpoint)(CACHEFILE, void*)); + void (*note_unpin_by_checkpoint)(CACHEFILE, void*), + void (*note_pin_by_backup)(CACHEFILE, void*), + void (*note_unpin_by_backup)(CACHEFILE, void*)); // Effect: Store some cachefile-specific user data. When the last reference to a cachefile is closed, we call close_userdata(). // Before starting a checkpoint, we call checkpoint_prepare_userdata(). // When the cachefile needs to be checkpointed, we call checkpoint_userdata(). diff --git a/ft/ft-internal.h b/ft/ft-internal.h index eec591d17..89025f9cb 100644 --- a/ft/ft-internal.h +++ b/ft/ft-internal.h @@ -197,7 +197,9 @@ struct ft { uint32_t num_txns; // A checkpoint is running. If true, then keep this header around for checkpoint, like a transaction bool pinned_by_checkpoint; - + // Number of backups that are using this FT. If it is nonzero, keep this header around until backup + // is completd. + uint32_t num_backups; // is this ft a blackhole? if so, all messages are dropped. bool blackhole; diff --git a/ft/ft.cc b/ft/ft.cc index 454bf1179..b09aed206 100644 --- a/ft/ft.cc +++ b/ft/ft.cc @@ -306,13 +306,42 @@ static void unpin_by_checkpoint_callback(FT ft, void *extra) { } // maps to cf->note_unpin_by_checkpoint -//Must be protected by ydb lock. -//Called by end_checkpoint, which grabs ydb lock around note_unpin +// Must be protected by ydb lock. +// Called by end_checkpoint, which grabs ydb lock around note_unpin static void ft_note_unpin_by_checkpoint (CACHEFILE UU(cachefile), void *header_v) { FT ft = (FT) header_v; toku_ft_remove_reference(ft, false, ZERO_LSN, unpin_by_checkpoint_callback, NULL); } + +// maps to cf->note_pin_by_backup +// Must be protected by ydb lock. +// Is only called by backup begin, which holds it +static void ft_note_pin_by_backup (CACHEFILE UU(cachefile), void *header_v) { + // Note: open_close lock is held by checkpoint begin + FT ft = (FT) header_v; + toku_ft_grab_reflock(ft); + assert(toku_ft_needed_unlocked(ft)); + ft->num_backups++; + toku_ft_release_reflock(ft); +} + +// Requires: the reflock is held. +static void unpin_by_backup_callback(FT ft, void *extra) { + invariant(extra == NULL); + invariant(ft->num_backups > 0); + ft->num_backups--; +} + +// maps to cf->note_unpin_by_backup +// Must be protected by ydb lock. +// Called by end_backup, which grabs ydb lock around note_unpin +static void ft_note_unpin_by_backup (CACHEFILE UU(cachefile), void *header_v) { + FT ft = (FT) header_v; + toku_ft_remove_reference(ft, false, ZERO_LSN, unpin_by_backup_callback, NULL); +} + + // // End of Functions that are callbacks to the cachefile ///////////////////////////////////////////////////////////////////////// @@ -332,38 +361,33 @@ static void setup_initial_ft_root_node(FT ft, BLOCKNUM blocknum) { } static void ft_init(FT ft, FT_OPTIONS options, CACHEFILE cf) { - // fake, prevent unnecessary upgrade logic - ft->layout_version_read_from_disk = FT_LAYOUT_VERSION; - ft->checkpoint_header = NULL; + // fake, prevent unnecessary upgrade logic + ft->layout_version_read_from_disk = FT_LAYOUT_VERSION; + ft->checkpoint_header = NULL; - toku_list_init(&ft->live_ft_handles); + toku_list_init(&ft->live_ft_handles); - // intuitively, the comparator points to the FT's cmp descriptor - ft->cmp.create(options->compare_fun, &ft->cmp_descriptor, options->memcmp_magic); - ft->update_fun = options->update_fun; + // intuitively, the comparator points to the FT's cmp descriptor + ft->cmp.create(options->compare_fun, &ft->cmp_descriptor, + options->memcmp_magic); + ft->update_fun = options->update_fun; - if (ft->cf != NULL) { - assert(ft->cf == cf); - } - ft->cf = cf; - ft->in_memory_stats = ZEROSTATS; + if (ft->cf != NULL) { + assert(ft->cf == cf); + } + ft->cf = cf; + ft->in_memory_stats = ZEROSTATS; - setup_initial_ft_root_node(ft, ft->h->root_blocknum); - toku_cachefile_set_userdata(ft->cf, - ft, - ft_log_fassociate_during_checkpoint, - ft_close, - ft_free, - ft_checkpoint, - ft_begin_checkpoint, - ft_end_checkpoint, - ft_note_pin_by_checkpoint, - ft_note_unpin_by_checkpoint); + setup_initial_ft_root_node(ft, ft->h->root_blocknum); + toku_cachefile_set_userdata( + ft->cf, ft, ft_log_fassociate_during_checkpoint, ft_close, ft_free, + ft_checkpoint, ft_begin_checkpoint, ft_end_checkpoint, + ft_note_pin_by_checkpoint, ft_note_unpin_by_checkpoint, + ft_note_pin_by_backup, ft_note_unpin_by_backup); - ft->blocktable.verify_no_free_blocknums(); + ft->blocktable.verify_no_free_blocknums(); } - static FT_HEADER ft_header_create(FT_OPTIONS options, BLOCKNUM root_blocknum, TXNID root_xid_that_created) { @@ -455,7 +479,9 @@ int toku_read_ft_and_store_in_cachefile (FT_HANDLE ft_handle, CACHEFILE cf, LSN ft_begin_checkpoint, ft_end_checkpoint, ft_note_pin_by_checkpoint, - ft_note_unpin_by_checkpoint); + ft_note_unpin_by_checkpoint, + ft_note_pin_by_backup, + ft_note_unpin_by_backup); *header = ft; return 0; } @@ -475,7 +501,7 @@ static int ft_get_reference_count(FT ft) { uint32_t pinned_by_checkpoint = ft->pinned_by_checkpoint ? 1 : 0; int num_handles = toku_list_num_elements_est(&ft->live_ft_handles); - return pinned_by_checkpoint + ft->num_txns + num_handles; + return pinned_by_checkpoint + ft->num_txns + ft-> num_backups + num_handles; } // a ft is needed in memory iff its reference count is non-zero diff --git a/ft/tests/cachetable-pin-checkpoint.cc b/ft/tests/cachetable-pin-checkpoint.cc index 9632b199d..1a97a8214 100644 --- a/ft/tests/cachetable-pin-checkpoint.cc +++ b/ft/tests/cachetable-pin-checkpoint.cc @@ -358,21 +358,15 @@ cachetable_test (void) { toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr); const char *fname1 = TOKU_TEST_FILENAME; unlink(fname1); - r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0); + r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR | O_CREAT, + S_IRWXU | S_IRWXG | S_IRWXO); + assert(r == 0); toku_cachefile_set_userdata( - f1, - NULL, - &dummy_log_fassociate, - &dummy_close_usr, - &dummy_free_usr, - &dummy_chckpnt_usr, - &test_begin_checkpoint, - &dummy_end, - &dummy_note_pin, - &dummy_note_unpin - ); - + f1, NULL, &dummy_log_fassociate, &dummy_close_usr, &dummy_free_usr, + &dummy_chckpnt_usr, &test_begin_checkpoint, &dummy_end, &dummy_note_pin, + &dummy_note_unpin, &dummy_note_pin, &dummy_note_unpin); + toku_pthread_t time_tid; toku_pthread_t checkpoint_tid; toku_pthread_t move_tid[NUM_MOVER_THREADS]; diff --git a/ft/tests/cachetable-put-checkpoint.cc b/ft/tests/cachetable-put-checkpoint.cc index a159d448b..ef80623c7 100644 --- a/ft/tests/cachetable-put-checkpoint.cc +++ b/ft/tests/cachetable-put-checkpoint.cc @@ -487,20 +487,16 @@ cachetable_test (void) { toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr); const char *fname1 = TOKU_TEST_FILENAME; unlink(fname1); - r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0); + r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR | O_CREAT, + S_IRWXU | S_IRWXG | S_IRWXO); + assert(r == 0); toku_cachefile_set_userdata( - f1, - NULL, - &dummy_log_fassociate, - &dummy_close_usr, - &dummy_free_usr, + f1, NULL, &dummy_log_fassociate, &dummy_close_usr, &dummy_free_usr, &dummy_chckpnt_usr, test_begin_checkpoint, // called in begin_checkpoint - &dummy_end, - &dummy_note_pin, - &dummy_note_unpin - ); + &dummy_end, &dummy_note_pin, &dummy_note_unpin, &dummy_note_pin, + &dummy_note_unpin); toku_pthread_t time_tid; toku_pthread_t checkpoint_tid; diff --git a/ft/tests/cachetable-simple-close.cc b/ft/tests/cachetable-simple-close.cc index c1c4cb4f1..3b0000d7f 100644 --- a/ft/tests/cachetable-simple-close.cc +++ b/ft/tests/cachetable-simple-close.cc @@ -50,18 +50,10 @@ static void free_usr(CACHEFILE UU(cf), void* UU(p)) { } static void set_cf_userdata(CACHEFILE f1) { - toku_cachefile_set_userdata( - f1, - NULL, - &dummy_log_fassociate, - &close_usr, - &free_usr, - &dummy_chckpnt_usr, - &dummy_begin, - &dummy_end, - &dummy_note_pin, - &dummy_note_unpin - ); + toku_cachefile_set_userdata(f1, NULL, &dummy_log_fassociate, &close_usr, + &free_usr, &dummy_chckpnt_usr, &dummy_begin, + &dummy_end, &dummy_note_pin, &dummy_note_unpin, + &dummy_note_pin, &dummy_note_unpin); } bool keep_me; diff --git a/ft/tests/cachetable-test.h b/ft/tests/cachetable-test.h index acb859de0..c45c34edc 100644 --- a/ft/tests/cachetable-test.h +++ b/ft/tests/cachetable-test.h @@ -58,15 +58,9 @@ static void dummy_note_unpin(CACHEFILE UU(cf), void* UU(p)) { } static UU() void create_dummy_functions(CACHEFILE cf) { - void *ud = NULL; - toku_cachefile_set_userdata(cf, - ud, - &dummy_log_fassociate, - &dummy_close_usr, - &dummy_free_usr, - &dummy_chckpnt_usr, - &dummy_begin, - &dummy_end, - &dummy_note_pin, - &dummy_note_unpin); + void *ud = NULL; + toku_cachefile_set_userdata(cf, ud, &dummy_log_fassociate, &dummy_close_usr, + &dummy_free_usr, &dummy_chckpnt_usr, &dummy_begin, + &dummy_end, &dummy_note_pin, &dummy_note_unpin, + &dummy_note_pin, &dummy_note_unpin); }; diff --git a/ft/tests/fifo-test.cc b/ft/tests/fifo-test.cc index 7a63969b2..9ee944770 100644 --- a/ft/tests/fifo-test.cc +++ b/ft/tests/fifo-test.cc @@ -73,15 +73,17 @@ test_enqueue(int n) { if (i == 0) { xids = toku_xids_get_root_xids(); } else { - int r = toku_xids_create_child(toku_xids_get_root_xids(), &xids, (TXNID)i); - assert_zero(r); + int r = toku_xids_create_child(toku_xids_get_root_xids(), &xids, + (TXNID)i); + assert_zero(r); } MSN msn = next_dummymsn(); if (startmsn.msn == ZERO_MSN.msn) - startmsn = msn; - enum ft_msg_type type = (enum ft_msg_type) i; + startmsn = msn; + enum ft_msg_type type = (enum ft_msg_type)i; DBT k, v; - ft_msg msg(toku_fill_dbt(&k, thekey, thekeylen), toku_fill_dbt(&v, theval, thevallen), type, msn, xids); + ft_msg msg(toku_fill_dbt(&k, thekey, thekeylen), + toku_fill_dbt(&v, theval, thevallen), type, msn, xids); msg_buffer.enqueue(msg, true, nullptr); toku_xids_destroy(&xids); toku_free(thekey); diff --git a/ft/tests/ft-in-backup-test.cc b/ft/tests/ft-in-backup-test.cc new file mode 100644 index 000000000..59ed29803 --- /dev/null +++ b/ft/tests/ft-in-backup-test.cc @@ -0,0 +1,176 @@ +/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: +#ident "$Id$" +/*====== +This file is part of PerconaFT. + + +Copyright (c) 2006, 2017, Percona and/or its affiliates. All rights reserved. + + PerconaFT is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, + as published by the Free Software Foundation. + + PerconaFT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with PerconaFT. If not, see . + +---------------------------------------- + + PerconaFT is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License, version 3, + as published by the Free Software Foundation. + + PerconaFT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with PerconaFT. If not, see . +======= */ + +#ident \ + "Copyright (c) 2006, 2017, Percona and/or its affiliates. All rights reserved." + +#include "cachetable/checkpoint.h" +#include "test.h" + +static TOKUTXN const null_txn = 0; +static const char *fname = TOKU_TEST_FILENAME; + +/* test for_backup in ft_close */ +static void test_in_backup() { + int r; + CACHETABLE ct; + FT_HANDLE ft; + unlink(fname); + + toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); + // TEST1 : normal case without backup + r = toku_open_ft_handle(fname, 1, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + { + DBT k, v; + toku_ft_insert(ft, toku_fill_dbt(&k, "hello", 6), + toku_fill_dbt(&v, "there", 6), null_txn); + } + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + ft_lookup_and_check_nodup(ft, "hello", "there"); + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + toku_cachetable_close(&ct); + + // TEST2: new insert in the middle of a backup before backup finishes + // should be invisible + toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + + toku_cachetable_begin_backup(ct); + // this key/value is still in fly since we are in the middle of a back up + { + DBT k, v; + toku_ft_insert(ft, toku_fill_dbt(&k, "halou", 6), + toku_fill_dbt(&v, "not there", 10), null_txn); + } + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + ft_lookup_and_check_nodup(ft, "halou", "not there"); + + // because we are in backup, so the FT header is stale after + // cachefile & cachetable closed. + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + toku_cachetable_close(&ct); + + // check the in fly key/value, it shouldn't exist + toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + ft_lookup_and_fail_nodup(ft, (char *)"halou"); + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + // the backup ends here. + toku_cachetable_end_backup(ct); + toku_cachetable_close(&ct); + + // TEST3: new insert in the middle of a backup should become visible + // once the backup completes. There is no ft leak here as once the + // backup completes the ft ref drops to zero and gets evicted. + toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + + toku_cachetable_begin_backup(ct); + // this key/value is still in fly since we are in the middle of a backup + { + DBT k, v; + toku_ft_insert(ft, toku_fill_dbt(&k, "halou1", 7), + toku_fill_dbt(&v, "not there", 10), null_txn); + } + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + ft_lookup_and_check_nodup(ft, "halou1", "not there"); + + // because we are in backup, so the FT header is stale after + // cachefile & cachetable closed + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + // but this time we ends the backup here before checking the new insert. + toku_cachetable_end_backup(ct); + toku_cachetable_close(&ct); + + toku_cachetable_create(&ct, 0, ZERO_LSN, nullptr); + r = toku_open_ft_handle(fname, 0, &ft, 1 << 12, 1 << 9, + TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, + toku_builtin_compare_fun); + assert_zero(r); + ft_lookup_and_check_nodup(ft, "halou1", "not there"); + r = toku_close_ft_handle_nolsn(ft, 0); + assert_zero(r); + toku_cachetable_close(&ct); +} + +int test_main(int argc, const char *argv[]) { + default_parse_args(argc, argv); + test_in_backup(); + if (verbose) + printf("test ok\n"); + return 0; +} diff --git a/src/ydb.cc b/src/ydb.cc index a172773bc..85e66d1c4 100644 --- a/src/ydb.cc +++ b/src/ydb.cc @@ -1868,7 +1868,10 @@ env_checkpointing_postpone(DB_ENV * env) { HANDLE_PANICKED_ENV(env); int r = 0; if (!env_opened(env)) r = EINVAL; - else toku_checkpoint_safe_client_lock(); + else { + toku_checkpoint_safe_client_lock(); + toku_cachetable_begin_backup(env->i->cachetable); + } return r; } @@ -1877,7 +1880,10 @@ env_checkpointing_resume(DB_ENV * env) { HANDLE_PANICKED_ENV(env); int r = 0; if (!env_opened(env)) r = EINVAL; - else toku_checkpoint_safe_client_unlock(); + else { + toku_cachetable_end_backup(env->i->cachetable); + toku_checkpoint_safe_client_unlock(); + } return r; }