diff options
author | Etienne Petrel <etienne.petrel@mongodb.com> | 2022-09-22 16:36:31 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-22 17:42:18 +0000 |
commit | d0b1a6fd3a3cf13f1dd33c2b12c54f878977e1af (patch) | |
tree | bb2019218a82de865b7f1289d3d884124bad420e | |
parent | 3e9738ba8ed59fedc132254ab3ddf789a2b1a7b4 (diff) | |
download | mongo-d0b1a6fd3a3cf13f1dd33c2b12c54f878977e1af.tar.gz |
Import wiredtiger: c9c52d672430ef4adb30dc01c4f0c81aa948bedd from branch mongodb-master
ref: 8dc9a88dbb..c9c52d6724
for: 6.2.0-rc0
Revert "WT-9851 Support bounded cursor next and prev traversal in FLCS (#8273)" (#8294)
9 files changed, 52 insertions, 121 deletions
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data index c1845df0a1e..706ca1fb355 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": "8dc9a88dbbf57da763cf3ae440de7b3b49cb86ab" + "commit": "c9c52d672430ef4adb30dc01c4f0c81aa948bedd" } diff --git a/src/third_party/wiredtiger/src/btree/bt_curnext.c b/src/third_party/wiredtiger/src/btree/bt_curnext.c index 1dc6b86854c..2b99c6fbae3 100644 --- a/src/third_party/wiredtiger/src/btree/bt_curnext.c +++ b/src/third_party/wiredtiger/src/btree/bt_curnext.c @@ -13,9 +13,8 @@ * Return the next entry on the append list. */ static inline int -__cursor_fix_append_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_out_of_boundsp) +__cursor_fix_append_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart) { - WT_DECL_RET; WT_SESSION_IMPL *session; session = CUR2S(cbt); @@ -39,9 +38,7 @@ __cursor_fix_append_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool * it to 1, which is correct. */ __cursor_set_recno(cbt, cbt->recno + 1); - if ((ret = __wt_btcur_bounds_early_exit(session, cbt, true, key_out_of_boundsp)) == WT_NOTFOUND) - WT_STAT_CONN_DATA_INCR(session, cursor_bounds_next_early_exit); - WT_RET(ret); + /* * Fixed-width column store appends are inherently non-transactional. Even a non-visible update * by a concurrent or aborted transaction changes the effective end of the data. The effect is @@ -78,9 +75,8 @@ restart_read: * Move to the next, fixed-length column-store item. */ static inline int -__cursor_fix_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_out_of_boundsp) +__cursor_fix_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart) { - WT_DECL_RET; WT_PAGE *page; WT_SESSION_IMPL *session; @@ -111,9 +107,6 @@ __cursor_fix_next(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_ou new_page: restart_read: - if ((ret = __wt_btcur_bounds_early_exit(session, cbt, true, key_out_of_boundsp)) == WT_NOTFOUND) - WT_STAT_CONN_DATA_INCR(session, cursor_bounds_next_early_exit); - WT_RET(ret); /* We only have one slot. */ cbt->slot = 0; @@ -840,7 +833,7 @@ __wt_btcur_next_prefix(WT_CURSOR_BTREE *cbt, WT_ITEM *prefix, bool truncating) WT_ASSERT(session, page != NULL); switch (page->type) { case WT_PAGE_COL_FIX: - ret = __cursor_fix_append_next(cbt, newpage, restart, &key_out_of_bounds); + ret = __cursor_fix_append_next(cbt, newpage, restart); break; case WT_PAGE_COL_VAR: ret = __cursor_var_append_next(cbt, newpage, restart, &skipped, &key_out_of_bounds); @@ -866,7 +859,7 @@ __wt_btcur_next_prefix(WT_CURSOR_BTREE *cbt, WT_ITEM *prefix, bool truncating) } else if (page != NULL) { switch (page->type) { case WT_PAGE_COL_FIX: - ret = __cursor_fix_next(cbt, newpage, restart, &key_out_of_bounds); + ret = __cursor_fix_next(cbt, newpage, restart); break; case WT_PAGE_COL_VAR: ret = __cursor_var_next(cbt, newpage, restart, &skipped, &key_out_of_bounds); diff --git a/src/third_party/wiredtiger/src/btree/bt_curprev.c b/src/third_party/wiredtiger/src/btree/bt_curprev.c index 07d0053db65..20a0172ba7e 100644 --- a/src/third_party/wiredtiger/src/btree/bt_curprev.c +++ b/src/third_party/wiredtiger/src/btree/bt_curprev.c @@ -120,9 +120,8 @@ restart: * Return the previous fixed-length entry on the append list. */ static inline int -__cursor_fix_append_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_out_of_boundsp) +__cursor_fix_append_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart) { - WT_DECL_RET; WT_SESSION_IMPL *session; session = CUR2S(cbt); @@ -185,11 +184,6 @@ __cursor_fix_append_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool else __cursor_set_recno(cbt, cbt->recno - 1); - if ((ret = __wt_btcur_bounds_early_exit(session, cbt, false, key_out_of_boundsp)) == - WT_NOTFOUND) - WT_STAT_CONN_DATA_INCR(session, cursor_bounds_prev_early_exit); - WT_RET(ret); - if (F_ISSET(&cbt->iface, WT_CURSTD_KEY_ONLY)) return (0); @@ -224,9 +218,8 @@ restart_read: * Move to the previous, fixed-length column-store item. */ static inline int -__cursor_fix_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_out_of_boundsp) +__cursor_fix_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart) { - WT_DECL_RET; WT_PAGE *page; WT_SESSION_IMPL *session; @@ -257,11 +250,6 @@ __cursor_fix_prev(WT_CURSOR_BTREE *cbt, bool newpage, bool restart, bool *key_ou new_page: restart_read: - if ((ret = __wt_btcur_bounds_early_exit(session, cbt, false, key_out_of_boundsp)) == - WT_NOTFOUND) - WT_STAT_CONN_DATA_INCR(session, cursor_bounds_prev_early_exit); - WT_RET(ret); - /* We only have one slot. */ cbt->slot = 0; @@ -793,7 +781,7 @@ __wt_btcur_prev(WT_CURSOR_BTREE *cbt, bool truncating) WT_ASSERT(session, page != NULL); switch (page->type) { case WT_PAGE_COL_FIX: - ret = __cursor_fix_append_prev(cbt, newpage, restart, &key_out_of_bounds); + ret = __cursor_fix_append_prev(cbt, newpage, restart); break; case WT_PAGE_COL_VAR: ret = __cursor_var_append_prev(cbt, newpage, restart, &skipped, &key_out_of_bounds); @@ -812,7 +800,7 @@ __wt_btcur_prev(WT_CURSOR_BTREE *cbt, bool truncating) if (page != NULL) { switch (page->type) { case WT_PAGE_COL_FIX: - ret = __cursor_fix_prev(cbt, newpage, restart, &key_out_of_bounds); + ret = __cursor_fix_prev(cbt, newpage, restart); break; case WT_PAGE_COL_VAR: ret = __cursor_var_prev(cbt, newpage, restart, &skipped, &key_out_of_bounds); diff --git a/src/third_party/wiredtiger/src/btree/bt_cursor.c b/src/third_party/wiredtiger/src/btree/bt_cursor.c index 9f294f18f2f..40d9337c1d6 100644 --- a/src/third_party/wiredtiger/src/btree/bt_cursor.c +++ b/src/third_party/wiredtiger/src/btree/bt_cursor.c @@ -300,24 +300,21 @@ __wt_cursor_valid(WT_CURSOR_BTREE *cbt, WT_ITEM *key, uint64_t recno, bool *vali * update that's been deleted is not a valid key/value pair). */ if (cbt->ins != NULL) { - if (btree->type == BTREE_ROW && WT_CURSOR_BOUNDS_SET(&cbt->iface) && key == NULL) { + if (WT_CURSOR_BOUNDS_SET(&cbt->iface)) { /* Get the insert list key. */ - tmp_key.data = WT_INSERT_KEY(cbt->ins); - tmp_key.size = WT_INSERT_KEY_SIZE(cbt->ins); - } - /* - * A number of different scenarios are handled here, we can have a key provided to the - * function for row-store. If there isn't a key for row-store then we need to get it from - * the insert list. The key held on the cursor isn't considered here. Additionally column - * store is handled here by passing the recno. - */ - WT_RET(__btcur_bounds_contains_key(session, &cbt->iface, key == NULL ? &tmp_key : key, - cbt->recno, &key_out_of_bounds, NULL)); - - /* The key value pair we were trying to return weren't within the given bounds. */ - if (key_out_of_bounds) - return (0); + if (key == NULL && btree->type == BTREE_ROW) { + tmp_key.data = WT_INSERT_KEY(cbt->ins); + tmp_key.size = WT_INSERT_KEY_SIZE(cbt->ins); + WT_RET(__btcur_bounds_contains_key( + session, &cbt->iface, &tmp_key, WT_RECNO_OOB, &key_out_of_bounds, NULL)); + } else + WT_RET(__btcur_bounds_contains_key( + session, &cbt->iface, key, cbt->recno, &key_out_of_bounds, NULL)); + /* The key value pair we were trying to return weren't within the given bounds. */ + if (key_out_of_bounds) + return (0); + } WT_RET(__wt_txn_read_upd_list(session, cbt, cbt->ins->upd)); if (cbt->upd_value->type != WT_UPDATE_INVALID) { if (cbt->upd_value->type == WT_UPDATE_TOMBSTONE) @@ -328,19 +325,6 @@ __wt_cursor_valid(WT_CURSOR_BTREE *cbt, WT_ITEM *key, uint64_t recno, bool *vali } /* - * The previous call to the contains key function handles insert list scenarios. If we don't - * have an insert list then we should check again against the recno. We can't check for - * row-store here as the key is extracted later in the function. - */ - if (btree->type != BTREE_ROW) { - WT_RET(__btcur_bounds_contains_key( - session, &cbt->iface, NULL, cbt->recno, &key_out_of_bounds, NULL)); - /* The key value pair we were trying to return weren't within the given bounds. */ - if (key_out_of_bounds) - return (0); - } - - /* * If we don't have an insert object, or in the case of column-store, there's an insert object * but no update was visible to us and the key on the page is the same as the insert object's * key, and the slot as set by the search function is valid, we can use the original page @@ -396,6 +380,12 @@ __wt_cursor_valid(WT_CURSOR_BTREE *cbt, WT_ITEM *key, uint64_t recno, bool *vali if (__wt_cell_type(cell) == WT_CELL_DEL) return (0); + WT_RET(__btcur_bounds_contains_key( + session, &cbt->iface, NULL, cbt->recno, &key_out_of_bounds, NULL)); + /* The key value pair we were trying to return weren't within the given bounds. */ + if (key_out_of_bounds) + return (0); + /* * Check for an update. For column store, modifications are handled with insert lists, so an * insert can have the same key as an on-page or history store object. Setting update here, diff --git a/src/third_party/wiredtiger/src/cursor/cur_std.c b/src/third_party/wiredtiger/src/cursor/cur_std.c index 4afd6533cf1..b047c06221c 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_std.c +++ b/src/third_party/wiredtiger/src/cursor/cur_std.c @@ -1187,6 +1187,9 @@ __wt_cursor_bound(WT_CURSOR *cursor, const char *config) CURSOR_API_CALL_CONF(cursor, session, bound, config, cfg, NULL); + if (CUR2BT(cursor)->type == BTREE_COL_FIX) + WT_ERR_MSG(session, EINVAL, "setting bounds is not compatible with fixed column store."); + if (F_ISSET(cursor, WT_CURSTD_PREFIX_SEARCH)) WT_ERR_MSG(session, EINVAL, "setting bounds is not compatible with prefix search."); diff --git a/src/third_party/wiredtiger/test/suite/test_cursor_bound02.py b/src/third_party/wiredtiger/test/suite/test_cursor_bound02.py index f6a73acfea7..459c9aabd85 100644 --- a/src/third_party/wiredtiger/test/suite/test_cursor_bound02.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor_bound02.py @@ -46,7 +46,6 @@ class test_cursor_bound02(bound_base): key_formats = [ ('string', dict(key_format='S')), ('var', dict(key_format='r')), - ('fix', dict(key_format='r')), ('int', dict(key_format='i')), ('bytes', dict(key_format='u')), ('composite_string', dict(key_format='SSS')), @@ -56,7 +55,6 @@ class test_cursor_bound02(bound_base): value_formats = [ ('string', dict(value_format='S')), - ('fix-byte', dict(value_format='8t')), ('complex-string', dict(value_format='SS')), ] @@ -69,10 +67,8 @@ class test_cursor_bound02(bound_base): def test_bound_api(self): uri = self.uri + self.file_name create_params = 'value_format={},key_format={}'.format(self.value_format, self.key_format) - if self.use_colgroup and self.value_format != '8t': + if self.use_colgroup: create_params += self.gen_colgroup_create_param() - else: - self.use_colgroup = False self.session.create(uri, create_params) # Add in column groups. @@ -142,15 +138,10 @@ class test_cursor_bound02(bound_base): def test_bound_api_reset(self): - # Fixed length bit arrays don't work well with colgroups. - if (self.value_format == '8t' and self.use_colgroup): - return uri = self.uri + self.file_name create_params = 'value_format={},key_format={}'.format(self.value_format, self.key_format) - if self.use_colgroup and self.value_format != '8t': + if self.use_colgroup: create_params += self.gen_colgroup_create_param() - else: - self.use_colgroup = False self.session.create(uri, create_params) # Add in column groups. if self.use_colgroup: @@ -173,7 +164,7 @@ class test_cursor_bound02(bound_base): cursor.reset() self.assertEqual(self.set_bounds(cursor, 99, "lower"), 0) - # Test bound API: Test that cursor reset works the clearing bounds both ways. + # Test bound API: Test that cursor reset works the clearing bounds both ways. self.assertEqual(self.set_bounds(cursor, 50, "lower"), 0) cursor.reset() self.assertEqual(self.set_bounds(cursor, 20, "lower"), 0) @@ -200,15 +191,10 @@ class test_cursor_bound02(bound_base): cursor.reset() def test_bound_api_clear(self): - # Fixed length bit arrays don't work well with colgroups. - if (self.value_format == '8t' and self.use_colgroup): - return uri = self.uri + self.file_name create_params = 'value_format={},key_format={}'.format(self.value_format, self.key_format) - if self.use_colgroup and self.value_format != '8t': + if self.use_colgroup: create_params += self.gen_colgroup_create_param() - else: - self.use_colgroup = False self.session.create(uri, create_params) # Add in column groups. if self.use_colgroup: @@ -227,12 +213,12 @@ class test_cursor_bound02(bound_base): self.assertEqual(cursor.bound("action=clear,bound=lower"), 0) self.assertEqual(self.set_bounds(cursor, 10, "upper"), 0) - # Test bound API: Test that clearing the upper bound works. + # Test bound API: Test that clearing the upper bound works. self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.set_bounds(cursor, 99, "lower"), '/Invalid argument/') self.assertEqual(cursor.bound("action=clear,bound=upper"), 0) self.assertEqual(self.set_bounds(cursor, 99, "lower"), 0) - # Test bound API: Test that clearing both of the bounds works. + # Test bound API: Test that clearing both of the bounds works. cursor.reset() self.assertEqual(self.set_bounds(cursor, 50, "upper"), 0) self.assertEqual(cursor.bound("action=clear"), 0) diff --git a/src/third_party/wiredtiger/test/suite/test_cursor_bound03.py b/src/third_party/wiredtiger/test/suite/test_cursor_bound03.py index 3e7daa3e5fb..fcbbb7e4b78 100644 --- a/src/third_party/wiredtiger/test/suite/test_cursor_bound03.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor_bound03.py @@ -43,8 +43,8 @@ class test_cursor_bound03(bound_base): ] key_formats = [ - ('var', dict(key_format='r')), ('string', dict(key_format='S')), + ('var', dict(key_format='r')), ('int', dict(key_format='i')), ('bytes', dict(key_format='u')), ('composite_string', dict(key_format='SSS')), @@ -54,9 +54,8 @@ class test_cursor_bound03(bound_base): value_formats = [ ('string', dict(value_format='S')), - ('fix', dict(value_format='8t')) # FIX-ME-WT-9589: Fix bug complex colgroups not returning records within bounds. - #('complex-string', dict(value_format='SS')), + # ('complex-string', dict(value_format='SS')), ] config = [ diff --git a/src/third_party/wiredtiger/test/suite/test_cursor_bound04.py b/src/third_party/wiredtiger/test/suite/test_cursor_bound04.py index e3061435731..b3e6fe0bc27 100644 --- a/src/third_party/wiredtiger/test/suite/test_cursor_bound04.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor_bound04.py @@ -56,7 +56,6 @@ class test_cursor_bound04(bound_base): value_formats = [ ('string', dict(value_format='S')), - ('fix', dict(value_format='8t')) # FIX-ME-WT-9589: Fix bug complex colgroups not returning records within bounds. # ('complex-string', dict(value_format='SS')), ] @@ -83,7 +82,7 @@ class test_cursor_bound04(bound_base): cursor.bound("action=clear,bound=lower") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) cursor.reset() # Test bound api: Test lower bound setting with positioned cursor. @@ -115,7 +114,7 @@ class test_cursor_bound04(bound_base): self.set_bounds(cursor, 55, "upper") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) cursor.set_key(self.gen_key(60)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.set_bounds(cursor, 50, "upper"), '/Invalid argument/') cursor.reset() @@ -123,7 +122,7 @@ class test_cursor_bound04(bound_base): self.set_bounds(cursor, 55, "upper") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) cursor.set_key(self.gen_key(90)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.set_bounds(cursor, 50, "upper"), '/Invalid argument/') @@ -132,7 +131,7 @@ class test_cursor_bound04(bound_base): self.set_bounds(cursor, 55, "upper") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) cursor.set_key(self.gen_key(10)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.set_bounds(cursor, 50, "upper"), '/Invalid argument/') @@ -151,7 +150,7 @@ class test_cursor_bound04(bound_base): self.set_bounds(cursor, 55, "upper") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: cursor.bound("bound=upper,inclusive=false"), '/Invalid argument/') cursor.reset() @@ -168,9 +167,9 @@ class test_cursor_bound04(bound_base): self.set_bounds(cursor, 55, "upper") self.assertEqual(cursor.next(), 0) key = cursor.get_key() - self.assertEqual(key, self.check_key(1 if self.flcs else self.start_key)) + self.assertEqual(key, self.check_key(self.start_key)) self.assertEqual(cursor.bound("action=clear"), 0) - self.cursor_traversal_bound(cursor, None, None, True, self.end_key - 1 if self.flcs else self.end_key - self.start_key) + self.cursor_traversal_bound(cursor, None, None, True, self.end_key - self.start_key) cursor.reset() cursor.close() @@ -230,7 +229,7 @@ class test_cursor_bound04(bound_base): key = cursor.get_key() self.assertEqual(key, self.check_key(45)) self.assertEqual(cursor.bound("action=clear"), 0) - self.cursor_traversal_bound(cursor, None, None, False, 45 - self.start_key if not self.flcs else 45 - 1) + self.cursor_traversal_bound(cursor, None, None, False, 45 - self.start_key) cursor.reset() self.set_bounds(cursor, 45, "upper") diff --git a/src/third_party/wiredtiger/test/suite/wtbound.py b/src/third_party/wiredtiger/test/suite/wtbound.py index f5c86b57bbf..8e814327f0e 100644 --- a/src/third_party/wiredtiger/test/suite/wtbound.py +++ b/src/third_party/wiredtiger/test/suite/wtbound.py @@ -108,18 +108,10 @@ class bound_base(wttest.WiredTigerTestCase): end_key = 79 lower_inclusive = True upper_inclusive = True - flcs = False def create_session_and_cursor(self, cursor_config=None): uri = self.uri + self.file_name create_params = 'value_format={},key_format={}'.format(self.value_format, self.key_format) - - if (self.value_format == '8t'): - # Colgroups generation doesn't seem to work with 8t format. - self.use_colgroup = False - if (self.key_format == 'r'): - self.flcs = True - if self.use_colgroup: create_params += self.gen_colgroup_create_param() self.session.create(uri, create_params) @@ -135,7 +127,7 @@ class bound_base(wttest.WiredTigerTestCase): self.session.begin_transaction() for i in range(self.start_key, self.end_key + 1): - cursor[self.gen_key(i)] = self.gen_val(str(i)) + cursor[self.gen_key(i)] = self.gen_val("value" + str(i)) self.session.commit_transaction() if (self.evict): @@ -190,8 +182,7 @@ class bound_base(wttest.WiredTigerTestCase): tuple_val.append(self.recno(i)) elif key == "i": tuple_val.append(i) - if (self.value_format == '8t'): - return int(int(i) & 0xff) + if (len(self.value_format) == 1): return tuple_val[0] else: @@ -235,11 +226,10 @@ class bound_base(wttest.WiredTigerTestCase): def cursor_traversal_bound(self, cursor, lower_key, upper_key, next=None, expected_count=None): if next == None: - next = self.next + next = self.direction start_range = self.start_key end_range = self.end_key - flcs_start_range = start_range if (upper_key): if (upper_key < end_range): @@ -253,15 +243,6 @@ class bound_base(wttest.WiredTigerTestCase): if (not self.lower_inclusive): start_range += 1 - # Special handling for fixed length column store where implicit records may exist. - if (self.flcs): - if (lower_key is not None): - if (lower_key < start_range): - flcs_start_range = lower_key - if (not self.lower_inclusive): - flcs_start_range += 1 - else: - flcs_start_range = 1 count = ret = 0 while True: @@ -288,12 +269,4 @@ class bound_base(wttest.WiredTigerTestCase): if (expected_count != None): self.assertEqual(expected_count, count) else: - # As a result of fix length column store creating implicit records during eviction we - # have assert that we either walked the expected range or a range with additional - # implicit records. - if (self.flcs): - range_without_implicit = end_range - start_range + 1 - range_with_implicit = end_range - flcs_start_range + 1 - self.assertTrue(count == range_with_implicit or count == range_without_implicit) - else: - self.assertEqual(end_range - start_range + 1, count) + self.assertEqual(end_range - start_range + 1, count) |