diff options
author | Chenhao Qu <chenhao.qu@mongodb.com> | 2021-05-24 06:20:39 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-24 06:46:40 +0000 |
commit | ebc7c43abc561839ca677ea66a690408866ac2f6 (patch) | |
tree | 4c53f513b1a0dbea4225c2c9bcd4c09225495862 | |
parent | 3bee503dad6203dccbcc8d63cb7c04b390f1a2c7 (diff) | |
download | mongo-ebc7c43abc561839ca677ea66a690408866ac2f6.tar.gz |
Import wiredtiger: 9acb906193234331be4978d07bb3ffe710ece6ed from branch mongodb-5.0
ref: ff7881f921..9acb906193
for: 5.0.1
WT-7135 Additional checks to detect when writing corrupted metadata
-rw-r--r-- | src/third_party/wiredtiger/import.data | 2 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/conn/conn_dhandle.c | 14 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/include/dhandle.h | 15 | ||||
-rw-r--r-- | src/third_party/wiredtiger/src/meta/meta_ckpt.c | 33 | ||||
-rw-r--r-- | src/third_party/wiredtiger/test/suite/test_alter03.py | 40 |
5 files changed, 80 insertions, 24 deletions
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data index 41670dd53e8..4485b83d435 100644 --- a/src/third_party/wiredtiger/import.data +++ b/src/third_party/wiredtiger/import.data @@ -2,5 +2,5 @@ "vendor": "wiredtiger", "github": "wiredtiger/wiredtiger.git", "branch": "mongodb-5.0", - "commit": "ff7881f9211c93b80162d6f1e61833195329771d" + "commit": "9acb906193234331be4978d07bb3ffe710ece6ed" } diff --git a/src/third_party/wiredtiger/src/conn/conn_dhandle.c b/src/third_party/wiredtiger/src/conn/conn_dhandle.c index 210ca733288..5e56a841de4 100644 --- a/src/third_party/wiredtiger/src/conn/conn_dhandle.c +++ b/src/third_party/wiredtiger/src/conn/conn_dhandle.c @@ -26,6 +26,9 @@ __conn_dhandle_config_clear(WT_SESSION_IMPL *session) __wt_free(session, *a); __wt_free(session, dhandle->cfg); __wt_free(session, dhandle->meta_base); +#ifdef HAVE_DIAGNOSTIC + __wt_free(session, dhandle->orig_meta_base); +#endif } /* @@ -85,6 +88,9 @@ __conn_dhandle_config_set(WT_SESSION_IMPL *session) cfg[3] = NULL; WT_ERR(__wt_strdup(session, WT_CONFIG_BASE(session, file_meta), &dhandle->cfg[0])); WT_ASSERT(session, dhandle->meta_base == NULL); +#ifdef HAVE_DIAGNOSTIC + WT_ASSERT(session, dhandle->orig_meta_base == NULL); +#endif WT_ERR(__wt_config_collapse(session, cfg, &tmp)); /* * Now strip out the checkpoint related items from the configuration string and that is now @@ -108,6 +114,14 @@ __conn_dhandle_config_set(WT_SESSION_IMPL *session) } dhandle->cfg[1] = metaconf; dhandle->meta_base = base; + dhandle->meta_base_length = base == NULL ? 0 : strlen(base); +#ifdef HAVE_DIAGNOSTIC + /* Save the original metadata value for further check to avoid writing corrupted data. */ + if (base == NULL) + dhandle->orig_meta_base = NULL; + else + WT_ERR(__wt_strdup(session, base, &dhandle->orig_meta_base)); +#endif return (0); err: diff --git a/src/third_party/wiredtiger/src/include/dhandle.h b/src/third_party/wiredtiger/src/include/dhandle.h index 9888c90d33e..01cfeffce6e 100644 --- a/src/third_party/wiredtiger/src/include/dhandle.h +++ b/src/third_party/wiredtiger/src/include/dhandle.h @@ -64,12 +64,15 @@ struct __wt_data_handle { TAILQ_ENTRY(__wt_data_handle) q; TAILQ_ENTRY(__wt_data_handle) hashq; - const char *name; /* Object name as a URI */ - uint64_t name_hash; /* Hash of name */ - const char *checkpoint; /* Checkpoint name (or NULL) */ - const char **cfg; /* Configuration information */ - const char *meta_base; /* Base metadata configuration */ - + const char *name; /* Object name as a URI */ + uint64_t name_hash; /* Hash of name */ + const char *checkpoint; /* Checkpoint name (or NULL) */ + const char **cfg; /* Configuration information */ + const char *meta_base; /* Base metadata configuration */ + size_t meta_base_length; /* Base metadata length */ +#ifdef HAVE_DIAGNOSTIC + const char *orig_meta_base; /* Copy of the base metadata configuration */ +#endif /* * Sessions holding a connection's data handle will have a non-zero reference count; sessions * using a connection's data handle will have a non-zero in-use count. Instances of cached diff --git a/src/third_party/wiredtiger/src/meta/meta_ckpt.c b/src/third_party/wiredtiger/src/meta/meta_ckpt.c index b5d0ae0b7a1..d4c8f316e5f 100644 --- a/src/third_party/wiredtiger/src/meta/meta_ckpt.c +++ b/src/third_party/wiredtiger/src/meta/meta_ckpt.c @@ -193,10 +193,12 @@ __wt_meta_checkpoint_clear(WT_SESSION_IMPL *session, const char *fname) static int __ckpt_set(WT_SESSION_IMPL *session, const char *fname, const char *v, bool use_base) { + WT_DATA_HANDLE *dhandle; WT_DECL_ITEM(tmp); WT_DECL_RET; + size_t meta_base_length; char *config, *newcfg; - const char *cfg[3], *str; + const char *cfg[3], *meta_base, *str; /* * If the caller knows we're on a path like checkpoints where we have a valid checkpoint and @@ -205,12 +207,35 @@ __ckpt_set(WT_SESSION_IMPL *session, const char *fname, const char *v, bool use_ * use the slower path through configuration parsing functions. */ config = newcfg = NULL; + dhandle = session->dhandle; str = v == NULL ? "checkpoint=(),checkpoint_backup_info=(),checkpoint_lsn=" : v; - if (use_base && session->dhandle != NULL) { + if (use_base && dhandle != NULL) { WT_ERR(__wt_scr_alloc(session, 0, &tmp)); - WT_ASSERT(session, strcmp(session->dhandle->name, fname) == 0); + WT_ASSERT(session, strcmp(dhandle->name, fname) == 0); + + /* Check the metadata is not corrupted. */ + meta_base = dhandle->meta_base; + meta_base_length = strlen(meta_base); + if (dhandle->meta_base_length != meta_base_length) + WT_ERR_PANIC(session, WT_PANIC, + "Corrupted metadata. The original metadata length was %lu while the new one is %lu.", + dhandle->meta_base_length, meta_base_length); +#ifdef HAVE_DIAGNOSTIC + if (!WT_STREQ(dhandle->orig_meta_base, meta_base)) + WT_ERR_PANIC(session, WT_PANIC, + "Corrupted metadata. The original metadata length was %lu while the new one is %lu. " + "The original metadata inserted was %s and the current " + "metadata is now %s.", + dhandle->meta_base_length, meta_base_length, dhandle->orig_meta_base, meta_base); +#endif + /* Concatenate the metadata base string with the checkpoint string. */ - WT_ERR(__wt_buf_fmt(session, tmp, "%s,%s", session->dhandle->meta_base, str)); + WT_ERR(__wt_buf_fmt(session, tmp, "%s,%s", meta_base, str)); + /* + * Check the new metadata length is at least as long as the original metadata string with + * the checkpoint base stripped out. + */ + WT_ASSERT(session, tmp->size >= dhandle->meta_base_length); WT_ERR(__wt_metadata_update(session, fname, tmp->mem)); } else { /* Retrieve the metadata for this file. */ diff --git a/src/third_party/wiredtiger/test/suite/test_alter03.py b/src/third_party/wiredtiger/test/suite/test_alter03.py index 2ff8ef3e568..f517721b26f 100644 --- a/src/third_party/wiredtiger/test/suite/test_alter03.py +++ b/src/third_party/wiredtiger/test/suite/test_alter03.py @@ -34,21 +34,27 @@ from wtscenario import make_scenarios class test_alter03(wttest.WiredTigerTestCase): name = "alter03" - def verify_metadata(self, table_metastr, file_metastr): - if table_metastr == '' and file_metastr == '': - return + def verify_metadata(self, table_metastr, lsm_metastr, file_metastr): c = self.session.open_cursor('metadata:', None, None) if table_metastr != '': - # We must find a table type entry for this object and it's value + # We must find a table type entry for this object and its value # should contain the provided table meta string. c.set_key('table:' + self.name) self.assertNotEqual(c.search(), wiredtiger.WT_NOTFOUND) value = c.get_value() self.assertTrue(value.find(table_metastr) != -1) + if lsm_metastr != '': + # We must find a lsm type entry for this object and its value + # should contain the provided lsm meta string. + c.set_key('lsm:' + self.name) + self.assertNotEqual(c.search(), wiredtiger.WT_NOTFOUND) + value = c.get_value() + self.assertTrue(value.find(lsm_metastr) != -1) + if file_metastr != '': - # We must find a file type entry for the object and it's value + # We must find a file type entry for the object and its value # should contain the provided file meta string. c.set_key('file:' + self.name + '.wt') self.assertNotEqual(c.search(), wiredtiger.WT_NOTFOUND) @@ -73,20 +79,20 @@ class test_alter03(wttest.WiredTigerTestCase): c.close() # Verify the string in the metadata - self.verify_metadata(app_meta_orig, app_meta_orig) + self.verify_metadata(app_meta_orig, '', app_meta_orig) # Alter app metadata and verify self.session.alter(uri, 'app_metadata="meta_data_2",') - self.verify_metadata('app_metadata="meta_data_2",', 'app_metadata="meta_data_2",') + self.verify_metadata('app_metadata="meta_data_2",', '', 'app_metadata="meta_data_2",') # Alter app metadata, explicitly asking for exclusive access and verify self.session.alter(uri, 'app_metadata="meta_data_3",exclusive_refreshed=true,') - self.verify_metadata('app_metadata="meta_data_3",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_3",', '', 'app_metadata="meta_data_3",') # Alter app metadata without taking exclusive lock and verify that only # table object gets modified self.session.alter(uri, 'app_metadata="meta_data_4",exclusive_refreshed=false,') - self.verify_metadata('app_metadata="meta_data_4",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_4",', '', 'app_metadata="meta_data_3",') # Open a cursor, insert some data and try to alter with session open. # We should fail unless we ask not to take an exclusive lock @@ -96,22 +102,22 @@ class test_alter03(wttest.WiredTigerTestCase): self.assertRaisesException(wiredtiger.WiredTigerError, lambda: self.session.alter(uri, 'app_metadata="meta_data_5",')) - self.verify_metadata('app_metadata="meta_data_4",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_4",', '', 'app_metadata="meta_data_3",') self.assertRaisesException(wiredtiger.WiredTigerError, lambda: self.session.alter(uri, 'exclusive_refreshed=true,app_metadata="meta_data_5",')) - self.verify_metadata('app_metadata="meta_data_4",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_4",', '', 'app_metadata="meta_data_3",') self.session.alter(uri, 'app_metadata="meta_data_5",exclusive_refreshed=false,') - self.verify_metadata('app_metadata="meta_data_5",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_5",', '', 'app_metadata="meta_data_3",') c2.close() # Close and reopen the connection. # Confirm we retain the app_metadata as expected after reopen self.reopen_conn() - self.verify_metadata('app_metadata="meta_data_5",', 'app_metadata="meta_data_3",') + self.verify_metadata('app_metadata="meta_data_5",', '', 'app_metadata="meta_data_3",') # Alter LSM: A non exclusive alter should not be allowed def test_alter03_lsm_app_metadata(self): @@ -121,12 +127,20 @@ class test_alter03(wttest.WiredTigerTestCase): self.session.create(uri, create_params + app_meta_orig) + # Try to alter app metadata without exclusive access and verify self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.alter(uri, 'exclusive_refreshed=false,app_metadata="meta_data_2",'), '/is applicable only on simple tables/') + self.verify_metadata('', 'app_metadata="meta_data_1",', '') + # Alter app metadata, explicitly asking for exclusive access and verify self.session.alter(uri, 'exclusive_refreshed=true,app_metadata="meta_data_2",') + self.verify_metadata('', 'app_metadata="meta_data_2",', '') + + # Alter app metadata and verify + self.session.alter(uri, 'app_metadata="meta_data_3",') + self.verify_metadata('', 'app_metadata="meta_data_3",', '') if __name__ == '__main__': wttest.run() |