diff options
author | Luke Chen <luke.chen@mongodb.com> | 2021-10-05 15:11:58 +1100 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-10-05 04:40:31 +0000 |
commit | 434b3b99b0cd5db494d0f6d38bd2ff76f7e4f0b8 (patch) | |
tree | 926582772527df4eff0666f1bc7cad3a672456e2 | |
parent | 97b2d24bef8dea8f6d9e069be6b810c9c0a9b5af (diff) | |
download | mongo-434b3b99b0cd5db494d0f6d38bd2ff76f7e4f0b8.tar.gz |
Import wiredtiger: 2b1f3d0eec137ceaab33071c1109507c5ebd0b0e from branch mongodb-master
ref: 2e1c641875..2b1f3d0eec
for: 5.1.0
WT-7992 Provide API to return the last key in a table regardless of visibility
23 files changed, 381 insertions, 22 deletions
diff --git a/src/third_party/wiredtiger/examples/c/ex_cursor.c b/src/third_party/wiredtiger/examples/c/ex_cursor.c index ac4fc1d22bc..14b8e866e8f 100644 --- a/src/third_party/wiredtiger/examples/c/ex_cursor.c +++ b/src/third_party/wiredtiger/examples/c/ex_cursor.c @@ -38,6 +38,7 @@ int cursor_search_near(WT_CURSOR *cursor); int cursor_insert(WT_CURSOR *cursor); int cursor_update(WT_CURSOR *cursor); int cursor_remove(WT_CURSOR *cursor); +int cursor_largest_key(WT_CURSOR *cursor); static const char *home; @@ -155,6 +156,14 @@ cursor_remove(WT_CURSOR *cursor) } /*! [cursor remove] */ +/*! [cursor largest key] */ +int +cursor_largest_key(WT_CURSOR *cursor) +{ + return (cursor->largest_key(cursor)); +} +/*! [cursor largest key] */ + int main(int argc, char *argv[]) { @@ -197,6 +206,7 @@ main(int argc, char *argv[]) error_check(cursor_search_near(cursor)); error_check(cursor_update(cursor)); error_check(cursor_remove(cursor)); + error_check(cursor_largest_key(cursor)); error_check(cursor->close(cursor)); /* Note: closing the connection implicitly closes open session(s). */ diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data index f5ec0ccfbb2..5f48424ce4c 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-master", - "commit": "2e1c64187513b3afe4a03b3d9d9aac998b6a0c94" + "commit": "2b1f3d0eec137ceaab33071c1109507c5ebd0b0e" } diff --git a/src/third_party/wiredtiger/lang/python/wiredtiger.i b/src/third_party/wiredtiger/lang/python/wiredtiger.i index 0105a5a70d6..5d221c6863b 100644 --- a/src/third_party/wiredtiger/lang/python/wiredtiger.i +++ b/src/third_party/wiredtiger/lang/python/wiredtiger.i @@ -582,6 +582,7 @@ NOTFOUND_OK(__wt_cursor::remove) NOTFOUND_OK(__wt_cursor::search) NOTFOUND_OK(__wt_cursor::update) NOTFOUND_OK(__wt_cursor::_modify) +NOTFOUND_OK(__wt_cursor::largest_key) ANY_OK(__wt_modify::__wt_modify) ANY_OK(__wt_modify::~__wt_modify) diff --git a/src/third_party/wiredtiger/src/cursor/cur_backup.c b/src/third_party/wiredtiger/src/cursor/cur_backup.c index fd416d3c452..820ea49aca0 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_backup.c +++ b/src/third_party/wiredtiger/src/cursor/cur_backup.c @@ -268,6 +268,7 @@ __wt_curbackup_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *other, __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curbackup_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_config.c b/src/third_party/wiredtiger/src/cursor/cur_config.c index ade673bba41..0fbf1066b27 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_config.c +++ b/src/third_party/wiredtiger/src/cursor/cur_config.c @@ -51,6 +51,7 @@ __wt_curconfig_open( __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curconfig_close); diff --git a/src/third_party/wiredtiger/src/cursor/cur_ds.c b/src/third_party/wiredtiger/src/cursor/cur_ds.c index 7139f1a8b08..c3e28dd5f59 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_ds.c +++ b/src/third_party/wiredtiger/src/cursor/cur_ds.c @@ -425,6 +425,7 @@ __wt_curds_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, con __curds_remove, /* remove */ __curds_reserve, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curds_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_dump.c b/src/third_party/wiredtiger/src/cursor/cur_dump.c index be4c1c7ef34..64e273f801b 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_dump.c +++ b/src/third_party/wiredtiger/src/cursor/cur_dump.c @@ -396,6 +396,7 @@ __wt_curdump_create(WT_CURSOR *child, WT_CURSOR *owner, WT_CURSOR **cursorp) __curdump_remove, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curdump_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_file.c b/src/third_party/wiredtiger/src/cursor/cur_file.c index ce54fd23abf..23c0a37776c 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_file.c +++ b/src/third_party/wiredtiger/src/cursor/cur_file.c @@ -671,6 +671,7 @@ __curfile_create(WT_SESSION_IMPL *session, WT_CURSOR *owner, const char *cfg[], __curfile_remove, /* remove */ __curfile_reserve, /* reserve */ __wt_cursor_reconfigure, /* reconfigure */ + __wt_cursor_largest_key, /* largest_key */ __curfile_cache, /* cache */ __curfile_reopen, /* reopen */ __curfile_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_hs.c b/src/third_party/wiredtiger/src/cursor/cur_hs.c index 2a2657b828b..00d419915ac 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_hs.c +++ b/src/third_party/wiredtiger/src/cursor/cur_hs.c @@ -1097,6 +1097,7 @@ __wt_curhs_open(WT_SESSION_IMPL *session, WT_CURSOR *owner, WT_CURSOR **cursorp) __curhs_remove, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curhs_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_index.c b/src/third_party/wiredtiger/src/cursor/cur_index.c index ea57c060196..c5c17e92453 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_index.c +++ b/src/third_party/wiredtiger/src/cursor/cur_index.c @@ -453,6 +453,7 @@ __wt_curindex_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curindex_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_join.c b/src/third_party/wiredtiger/src/cursor/cur_join.c index 7f00ea9bc3d..b721fe9d0ee 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_join.c +++ b/src/third_party/wiredtiger/src/cursor/cur_join.c @@ -576,6 +576,7 @@ __curjoin_entry_member( __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __wt_cursor_notsup); /* close */ @@ -1222,6 +1223,7 @@ __wt_curjoin_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, c __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curjoin_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_log.c b/src/third_party/wiredtiger/src/cursor/cur_log.c index f40ef6b7d1a..281050785d4 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_log.c +++ b/src/third_party/wiredtiger/src/cursor/cur_log.c @@ -340,6 +340,7 @@ __wt_curlog_open(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], W __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curlog_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_metadata.c b/src/third_party/wiredtiger/src/cursor/cur_metadata.c index cfd0191a782..f0b04128704 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_metadata.c +++ b/src/third_party/wiredtiger/src/cursor/cur_metadata.c @@ -575,6 +575,7 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owne __curmetadata_remove, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curmetadata_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_stat.c b/src/third_party/wiredtiger/src/cursor/cur_stat.c index cafa0c49b35..ca78b4bff52 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_stat.c +++ b/src/third_party/wiredtiger/src/cursor/cur_stat.c @@ -608,6 +608,7 @@ __wt_curstat_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *other, c __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curstat_close); /* close */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_std.c b/src/third_party/wiredtiger/src/cursor/cur_std.c index 776ad980d3f..ce683c17698 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_std.c +++ b/src/third_party/wiredtiger/src/cursor/cur_std.c @@ -1114,6 +1114,52 @@ err: } /* + * __wt_cursor_largest_key -- + * WT_CURSOR->largest_key default implementation.. + */ +int +__wt_cursor_largest_key(WT_CURSOR *cursor) +{ + WT_DECL_ITEM(key); + WT_DECL_RET; + WT_SESSION_IMPL *session; + bool ignore_tombstone; + + ignore_tombstone = F_ISSET(cursor, WT_CURSTD_IGNORE_TOMBSTONE); + CURSOR_API_CALL(cursor, session, largest_key, NULL); + + if (F_ISSET(session->txn, WT_TXN_SHARED_TS_READ)) + WT_ERR_MSG(session, EINVAL, "largest key cannot be called with a read timestamp"); + + WT_ERR(__wt_scr_alloc(session, 0, &key)); + + /* Reset the cursor to give up the cursor position. */ + WT_ERR(cursor->reset(cursor)); + + /* Ignore deletion */ + F_SET(cursor, WT_CURSTD_IGNORE_TOMBSTONE); + + /* Call cursor prev with read uncommitted isolation level. */ + WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED, ret = cursor->prev(cursor)); + WT_ERR(ret); + + /* Copy the key as we will reset the cursor after that. */ + WT_ERR(__wt_buf_set(session, key, cursor->key.data, cursor->key.size)); + WT_ERR(cursor->reset(cursor)); + WT_ERR(__wt_buf_set(session, &cursor->key, key->data, key->size)); + /* Set the key as external. */ + F_SET(cursor, WT_CURSTD_KEY_EXT); + +err: + if (!ignore_tombstone) + F_CLR(cursor, WT_CURSTD_IGNORE_TOMBSTONE); + __wt_scr_free(session, &key); + if (ret != 0) + WT_TRET(cursor->reset(cursor)); + API_END_RET(session, ret); +} + +/* * __wt_cursor_dup_position -- * Set a cursor to another cursor's position. */ diff --git a/src/third_party/wiredtiger/src/cursor/cur_table.c b/src/third_party/wiredtiger/src/cursor/cur_table.c index e4505544544..68776b18ba3 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_table.c +++ b/src/third_party/wiredtiger/src/cursor/cur_table.c @@ -102,6 +102,7 @@ __wt_apply_single_idx(WT_SESSION_IMPL *session, WT_INDEX *idx, WT_CURSOR *cur, __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __wt_cursor_notsup); /* close */ @@ -789,6 +790,31 @@ err: } /* + * __curtable_largest_key -- + * WT_CURSOR->largest_key method for the table cursor type. + */ +static int +__curtable_largest_key(WT_CURSOR *cursor) +{ + WT_CURSOR *primary; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_SESSION_IMPL *session; + + ctable = (WT_CURSOR_TABLE *)cursor; + JOINABLE_CURSOR_API_CALL(cursor, session, largest_key, NULL); + + WT_ERR(cursor->reset(cursor)); + primary = *ctable->cg_cursors; + WT_ERR(primary->largest_key(primary)); + +err: + if (ret != 0) + WT_TRET(cursor->reset(cursor)); + API_END_RET(session, ret); +} + +/* * __curtable_close -- * WT_CURSOR->close method for the table cursor type. */ @@ -968,6 +994,7 @@ __wt_curtable_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, __curtable_remove, /* remove */ __curtable_reserve, /* reserve */ __wt_cursor_reconfigure, /* reconfigure */ + __curtable_largest_key, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curtable_close); /* close */ diff --git a/src/third_party/wiredtiger/src/docs/cursor-ops.dox b/src/third_party/wiredtiger/src/docs/cursor-ops.dox index c9d75295ddc..82b763b563f 100644 --- a/src/third_party/wiredtiger/src/docs/cursor-ops.dox +++ b/src/third_party/wiredtiger/src/docs/cursor-ops.dox @@ -103,6 +103,16 @@ fail with ::WT_DUPLICATE_KEY if the record previously exists, and WT_CURSOR::update and WT_CURSOR::remove will fail with ::WT_NOTFOUND if the record does not previously exist. +@snippet ex_cursor.c cursor largest key + +The WT_SESSION::largest_key \c gets the largest key in a table regardless of +visibility. + +It can only be called without a read timestamp, otherwise it returns an invalid +argument error. Any following prev or next calls will behave as if they were +invoked on an unpositioned cursor no matter the largest key call is successful +or not. + @section cursor_error Cursor position after error After any cursor handle method failure, the cursor's position is diff --git a/src/third_party/wiredtiger/src/docs/spell.ok b/src/third_party/wiredtiger/src/docs/spell.ok index f34eace96d9..6a5b7f8dd5d 100644 --- a/src/third_party/wiredtiger/src/docs/spell.ok +++ b/src/third_party/wiredtiger/src/docs/spell.ok @@ -658,6 +658,7 @@ unescaped unicode uninstall unittest +unpositioned untyped uri useconds diff --git a/src/third_party/wiredtiger/src/include/cursor.h b/src/third_party/wiredtiger/src/include/cursor.h index 569da6aabaa..85797573e23 100644 --- a/src/third_party/wiredtiger/src/include/cursor.h +++ b/src/third_party/wiredtiger/src/include/cursor.h @@ -12,27 +12,27 @@ /* * Initialize a static WT_CURSOR structure. */ -#define WT_CURSOR_STATIC_INIT(n, get_key, get_value, set_key, set_value, compare, equals, next, \ - prev, reset, search, search_near, insert, modify, update, remove, reserve, reconfigure, cache, \ - reopen, close) \ - static const WT_CURSOR n = { \ - NULL, /* session */ \ - NULL, /* uri */ \ - NULL, /* key_format */ \ - NULL, /* value_format */ \ - get_key, get_value, set_key, set_value, compare, equals, next, prev, reset, search, \ - search_near, insert, modify, update, remove, reserve, close, reconfigure, cache, reopen, \ - 0, /* uri_hash */ \ - {NULL, NULL}, /* TAILQ_ENTRY q */ \ - 0, /* recno key */ \ - {0}, /* recno raw buffer */ \ - NULL, /* json_private */ \ - NULL, /* lang_private */ \ - {NULL, 0, NULL, 0, 0}, /* WT_ITEM key */ \ - {NULL, 0, NULL, 0, 0}, /* WT_ITEM value */ \ - 0, /* int saved_err */ \ - NULL, /* internal_uri */ \ - 0 /* uint32_t flags */ \ +#define WT_CURSOR_STATIC_INIT(n, get_key, get_value, set_key, set_value, compare, equals, next, \ + prev, reset, search, search_near, insert, modify, update, remove, reserve, reconfigure, \ + largest_key, cache, reopen, close) \ + static const WT_CURSOR n = { \ + NULL, /* session */ \ + NULL, /* uri */ \ + NULL, /* key_format */ \ + NULL, /* value_format */ \ + get_key, get_value, set_key, set_value, compare, equals, next, prev, reset, search, \ + search_near, insert, modify, update, remove, reserve, close, reconfigure, largest_key, \ + cache, reopen, 0, /* uri_hash */ \ + {NULL, NULL}, /* TAILQ_ENTRY q */ \ + 0, /* recno key */ \ + {0}, /* recno raw buffer */ \ + NULL, /* json_private */ \ + NULL, /* lang_private */ \ + {NULL, 0, NULL, 0, 0}, /* WT_ITEM key */ \ + {NULL, 0, NULL, 0, 0}, /* WT_ITEM value */ \ + 0, /* int saved_err */ \ + NULL, /* internal_uri */ \ + 0 /* uint32_t flags */ \ } struct __wt_cursor_backup { diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h index 266762fe94f..0d7a550094c 100644 --- a/src/third_party/wiredtiger/src/include/extern.h +++ b/src/third_party/wiredtiger/src/include/extern.h @@ -577,6 +577,8 @@ extern int __wt_cursor_key_order_init(WT_CURSOR_BTREE *cbt) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern int __wt_cursor_kv_not_set(WT_CURSOR *cursor, bool key) WT_GCC_FUNC_DECL_ATTRIBUTE((cold)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); +extern int __wt_cursor_largest_key(WT_CURSOR *cursor) + WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern int __wt_cursor_modify_notsup(WT_CURSOR *cursor, WT_MODIFY *entries, int nentries) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)); extern int __wt_cursor_modify_value_format_notsup(WT_CURSOR *cursor, WT_MODIFY *entries, diff --git a/src/third_party/wiredtiger/src/include/wiredtiger.in b/src/third_party/wiredtiger/src/include/wiredtiger.in index df084165b41..44eb86b1a32 100644 --- a/src/third_party/wiredtiger/src/include/wiredtiger.in +++ b/src/third_party/wiredtiger/src/include/wiredtiger.in @@ -661,6 +661,19 @@ struct __wt_cursor { */ int __F(reconfigure)(WT_CURSOR *cursor, const char *config); + /*! + * Get the largest key of the cursor regardless of visibility. + * The cursor is not positioned after calling this api. Only supported by data cursors. + * + * @snippet ex_all.c Reset the cursor + * + * @param cursor the cursor handle + * @errors + * If \c read_timestamp is set, EINVAL is returned. + * Also, calling \c WT_CURSOR::get_key after this api call returns EINVAL. + */ + int __F(largest_key)(WT_CURSOR *cursor); + /* * Protected fields, only to be used by cursor implementations. */ diff --git a/src/third_party/wiredtiger/src/lsm/lsm_cursor.c b/src/third_party/wiredtiger/src/lsm/lsm_cursor.c index 4c3aa2a3204..f1503d9bbf3 100644 --- a/src/third_party/wiredtiger/src/lsm/lsm_cursor.c +++ b/src/third_party/wiredtiger/src/lsm/lsm_cursor.c @@ -1685,6 +1685,7 @@ __wt_clsm_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, cons __clsm_remove, /* remove */ __clsm_reserve, /* reserve */ __wt_cursor_reconfigure, /* reconfigure */ + __wt_cursor_notsup, /* largest_key */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __wt_clsm_close); /* close */ diff --git a/src/third_party/wiredtiger/test/suite/test_cursor17.py b/src/third_party/wiredtiger/test/suite/test_cursor17.py new file mode 100644 index 00000000000..322b82a65f8 --- /dev/null +++ b/src/third_party/wiredtiger/test/suite/test_cursor17.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# +# Public Domain 2014-present MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# test_cursor17.py +# Test the largest_key interface under various scenarios. +# +import wttest +import wiredtiger +from wtdataset import SimpleDataSet, ComplexDataSet, ComplexLSMDataSet +from wtscenario import make_scenarios + +class test_cursor17(wttest.WiredTigerTestCase): + tablename = 'test_cursor17' + + # Enable the lsm tests once it is supported. + types = [ + ('file-row', dict(type='file:', keyformat='i', valueformat='i', dataset=SimpleDataSet)), + ('table-row', dict(type='table:', keyformat='i', valueformat='i', dataset=SimpleDataSet)), + ('file-var', dict(type='file:', keyformat='r', valueformat='i', dataset=SimpleDataSet)), + ('table-var', dict(type='table:', keyformat='r', valueformat='i', dataset=SimpleDataSet)), + ('file-fix', dict(type='file:', keyformat='r', valueformat='8t', dataset=SimpleDataSet)), + # ('lsm', dict(type='lsm:', keyformat='i', valueformat='i', dataset=SimpleDataSet)), + ('table-r-complex', dict(type='table:', keyformat='r', valueformat=None, + dataset=ComplexDataSet)), + # ('table-i-complex-lsm', dict(type='table:', keyformat='i', valueformat=None, + # dataset=ComplexLSMDataSet)), + ] + + scenarios = make_scenarios(types) + + def populate(self, rownum): + if self.valueformat != None: + self.ds = self.dataset(self, self.type + self.tablename, rownum, key_format=self.keyformat, value_format=self.valueformat) + else: + self.ds = self.dataset(self, self.type + self.tablename, rownum, key_format=self.keyformat) + self.ds.populate() + + def test_globally_deleted_key(self): + self.populate(100) + + # Delete the largest key. + cursor = self.session.open_cursor(self.type + self.tablename, None) + self.session.begin_transaction() + cursor.set_key(100) + self.assertEqual(cursor.remove(), 0) + self.session.commit_transaction() + + # Verify the key is not visible. + self.session.begin_transaction() + cursor.set_key(100) + if self.valueformat != '8t': + self.assertEqual(cursor.search(), wiredtiger.WT_NOTFOUND) + else: + self.assertEqual(cursor.search(), 0) + self.session.rollback_transaction() + + # Verify the largest key. + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + self.session.rollback_transaction() + + # Verify the key is still not visible after the largest call. + self.session.begin_transaction() + cursor.set_key(100) + if self.valueformat != '8t': + self.assertEqual(cursor.search(), wiredtiger.WT_NOTFOUND) + else: + self.assertEqual(cursor.search(), 0) + self.session.rollback_transaction() + + # Use evict cursor to evict the key from memory. + evict_cursor = self.session.open_cursor(self.type + self.tablename, None, "debug=(release_evict)") + evict_cursor.set_key(100) + if self.valueformat != '8t': + self.assertEquals(evict_cursor.search(), wiredtiger.WT_NOTFOUND) + else: + self.assertEquals(evict_cursor.search(), 0) + evict_cursor.close() + + # Verify the largest key changed. + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + if self.valueformat != '8t': + self.assertEqual(cursor.get_key(), 99) + else: + self.assertEquals(cursor.get_key(), 100) + self.session.rollback_transaction() + + def test_uncommitted_insert(self): + self.populate(100) + + session2 = self.setUpSessionOpen(self.conn) + cursor2 = session2.open_cursor(self.type + self.tablename, None) + session2.begin_transaction() + cursor2[101] = self.ds.value(101) + + cursor = self.session.open_cursor(self.type + self.tablename, None) + + # Verify the largest key. + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 101) + self.session.rollback_transaction() + + session2.rollback_transaction() + + def test_read_timestamp(self): + self.populate(100) + + cursor = self.session.open_cursor(self.type + self.tablename, None) + self.session.begin_transaction('read_timestamp=' + self.timestamp_str(5)) + # Expect the largest key to throw. + with self.expectedStderrPattern("largest key cannot be called with a read timestamp"): + try: + cursor.largest_key() + except wiredtiger.WiredTigerError as e: + gotException = True + self.pr('got expected exception: ' + str(e)) + self.assertTrue(str(e).find('nvalid argument') >= 0) + self.assertTrue(gotException, msg = 'expected exception') + self.session.rollback_transaction() + + def test_not_positioned(self): + self.populate(100) + + cursor = self.session.open_cursor(self.type + self.tablename, None) + # Verify the largest key. + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + + # Call prev + self.assertEqual(cursor.prev(), 0) + self.assertEqual(cursor.get_key(), 100) + + # Verify the largest key again. + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + + self.assertEqual(cursor.next(), 0) + self.assertEqual(cursor.get_key(), 1) + self.session.rollback_transaction() + + def test_get_value(self): + self.populate(100) + + cursor = self.session.open_cursor(self.type + self.tablename, None) + # Verify the largest key. + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + with self.expectedStderrPattern("requires value be set"): + try: + cursor.get_value() + except wiredtiger.WiredTigerError as e: + gotException = True + self.pr('got expected exception: ' + str(e)) + self.assertTrue(str(e).find('nvalid argument') >= 0) + self.assertTrue(gotException, msg = 'expected exception') + self.session.rollback_transaction() + + def test_empty_table(self): + self.populate(0) + + cursor = self.session.open_cursor(self.type + self.tablename, None) + # Verify the largest key. + self.session.begin_transaction() + self.assertEquals(cursor.largest_key(), wiredtiger.WT_NOTFOUND) + self.session.rollback_transaction() + + def test_fast_truncate(self): + self.populate(100) + + # evict all the pages + evict_cursor = self.session.open_cursor(self.type + self.tablename, None, "debug=(release_evict)") + self.session.begin_transaction() + for i in range(1, 101): + evict_cursor.set_key(i) + self.assertEquals(evict_cursor.search(), 0) + self.session.rollback_transaction() + evict_cursor.close() + + # truncate + cursor = self.session.open_cursor(self.type + self.tablename, None) + self.session.begin_transaction() + cursor.set_key(1) + self.session.truncate(None, cursor, None, None) + self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(5)) + + # verify the largest key + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + self.session.rollback_transaction() + + def test_slow_truncate(self): + self.populate(100) + + # truncate + cursor = self.session.open_cursor(self.type + self.tablename, None) + self.session.begin_transaction() + cursor.set_key(100) + self.session.truncate(None, cursor, None, None) + self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(5)) + + # verify the largest key + self.session.begin_transaction() + self.assertEqual(cursor.largest_key(), 0) + self.assertEqual(cursor.get_key(), 100) + self.session.rollback_transaction() |