Compare commits

...

11 Commits

Author SHA1 Message Date
Keith Bostic
d2f2eae6d7 WT-3373 Access violation due to a bug in internal page splitting (#3478)
When acquiring a lock on our parent internal page, we use the WT_REF.home
field to reference our parent page.  As a child of the parent page, we
prevent its eviction, but that's a weak guarantee. If the parent page
splits, and our WT_REF were to move with the split, the WT_REF.home field
might change underneath us and we could race, and end up attempting to
access an evicted page. Set the session page-index generation so if the
parent splits, it still can't be evicted.
2017-06-27 10:44:15 +10:00
sueloverso
89049da5f3 WT-3331 Get time into a local variable so we can read and use a consistent time (#3430) 2017-06-19 17:19:59 +00:00
Keith Bostic
0300f6d56c WT-3219 Make the clang-analyzer job fail when lint is introduced (#3400)
Quiet the four remaining clang-analyzer complaints.
2017-06-19 17:15:25 +00:00
Keith Bostic
cd2d31add1 WT-3297 support the gcc/clang -fvisibility=hidden flag (#3404) 2017-06-19 17:15:11 +00:00
sueloverso
b22f088bf3 WT-3327 Check for system clock ticking backwards (#3427) 2017-06-19 17:14:54 +00:00
Michael Cahill
0384f6ddbc WT-3362 Checkpoints shouldn't block drops. (#3459)
Testing has uncovered another case where drops can spin trying to lock a
checkpoint handle until a checkpoint completes.  This change fixes that
in two ways: attempting to lock (but not open) a handle won't spin, and
drop will always attempt to lock the live tree before locking any
checkpoint handles.
2017-06-19 17:12:32 +00:00
Don Anderson
ef9d122dd1 WT-3369 WT_CURSOR->uri should always match the URI used to open the cursor (#3464) 2017-06-19 15:23:54 +00:00
Michael Cahill
04a1578300 WT-3356 Use atomic reads of rwlocks. (#3454)
* WT-3356 Use atomic reads of rwlocks.
  
  Previously we had some conditions that checked several fields within a rwlock by indirecting to the live structure.  Switch to always doing a read of the full 64-bit value, then using local reads from the copy.
  
  Otherwise, we're relying on the compiler and the memory model to order the structure accesses in "code execution order".  That could explain assertion failures and/or incorrect behavior with the new rwlock implementation.

* Change all waits to 10ms.

  Previously when stalling waiting to get into the lock we would wait for 1ms, but once queued we waited forever.  The former is probably too aggressive (burns too much CPU when we should be able to wait for a notification), and the latter is dangerous if a notification is ever lost (a thread with a ticket may never wake up).
2017-06-07 07:35:40 +10:00
Michael Cahill
42c3687558 WT-3354 Fix bugs found by Coverity. (#3451)
* WT-3354 Fix bugs found by Coverity.

* two cases where error checking for rwlocks should goto the error label for cleanup.
* LSM code not restoring isolation if a checkpoint fails part way through

* Take care with ordering an assertion after a read barrier.

We just had an assertion failure on PPC, and from inspection it looks
like read in the assertion could be scheduled before read that sees the
ticket allocated.  We have a read barrier in this path to protect
against exactly that kind of thing happening to application data, move
the assertion after it so our diagnostics are also safe.
2017-06-07 07:35:20 +10:00
Michael Cahill
1bcb9a0cc4 WT-3345 Tune WiredTiger's read/write locks. (#3446)
* Add a workload that stresses rwlock performance under various conditions (including `threads >> cores`), tune read and write lock operations to only spin when it is likely to help, and to back off to a condition variable when there is heavy contention.

* New rwlock implementation: queue readers and writers separately, don't enforce fairness among readers or if the lock is overwhelmed.

* Switch to a spinlock whenever we need to lock a page.

Previously we had a read/write lock in the __wt_page structure that was only ever acquired in write mode, plus a spinlock in the page->modify structure.  Switch to using the spinlock for everything.

One slight downside of this change is that we can no longer precisely determine whether a page is locked based on the status of the spinlock (since another page sharing the same lock could be holding it in the places where we used to check).  Since that was only ever used
for diagnostic / debugging purposes, I think the benefit of the change outweighs this issue.

* Fix a bug where a failure during `__wt_curfile_create` caused a data handle to be released twice.  This is caught by the sanity checking assertions in the new read/write lock code.

* Split may be holding a page lock when restoring update.  Tell the restore code we have the page exclusive and no further locking is required.

* Allocate a spinlock for each modified page.

Using shared page locks for mulitple operations that need to lock a page (including inserts and reconciliation) resulted in self-deadlock when the lookaside table was used.  That's because reconciliation held a page lock, then caused inserts to the lookaside table, which acquired the page lock for a page in the lookaside table.  With a shared set of page locks, they could both be the same lock.

Switch (back?) to allocating a spinlock per modified page.  Earlier in this ticket we saved some space in __wt_page, so growing __wt_page_modify is unlikely to be noticeable.

* Tweak padding and position of the spinlock in WT_PAGE_MODIFY to claw back some bytes.

Move evict_pass_gen to the end of WT_PAGE: on inspection, it should be a cold field relative to the others, which now fit in one x86 cache line.
(cherry picked from commit 42daa132f2)
2017-06-02 13:27:16 +10:00
Alex Gorrod
ba73da9cd7 WT-3293 Don't explicitly mark internal symbols hidden. (#3398)
It messes with external stack decoders (e.g., MongoDB's built-in heap profiling).
(cherry picked from commit 96ee1d3f21)
2017-06-02 12:48:51 +10:00
64 changed files with 1739 additions and 1319 deletions

3
dist/s_prototypes vendored
View File

@@ -42,9 +42,6 @@ proto()
-e '# Add the warn_unused_result attribute to any external' \
-e '# functions that return an int.' \
-e '/^extern int /s/$/ WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result))/' \
-e '# Add the hidden attribute to any external functions without' \
-e '# an explicit visibility.' \
-e '/visibility/!s/$/ WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")))/' \
-e 's/$/;/' \
-e p < $1
}

1
dist/s_string.ok vendored
View File

@@ -731,6 +731,7 @@ fsyncLock
fsyncs
ftruncate
func
fvisibility
gcc
gdb
ge

1
dist/stat_data.py vendored
View File

@@ -150,6 +150,7 @@ connection_stats = [
ConnStat('read_io', 'total read I/Os'),
ConnStat('rwlock_read', 'pthread mutex shared lock read-lock calls'),
ConnStat('rwlock_write', 'pthread mutex shared lock write-lock calls'),
ConnStat('time_travel', 'detected system time went backwards'),
ConnStat('write_io', 'total write I/Os'),
##########################################

View File

@@ -440,7 +440,7 @@ __wt_async_destroy(WT_SESSION_IMPL *session)
session, async->worker_tids[i]));
async->worker_tids[i] = 0;
}
WT_TRET(__wt_cond_destroy(session, &async->flush_cond));
__wt_cond_destroy(session, &async->flush_cond);
/* Close the server threads' sessions. */
for (i = 0; i < conn->async_workers; i++)

View File

@@ -60,7 +60,7 @@ __compact_rewrite(WT_SESSION_IMPL *session, WT_REF *ref, bool *skipp)
*/
if (mod->rec_result == WT_PM_REC_REPLACE ||
mod->rec_result == WT_PM_REC_MULTIBLOCK)
__wt_writelock(session, &page->page_lock);
WT_PAGE_LOCK(session, page);
if (mod->rec_result == WT_PM_REC_REPLACE)
ret = bm->compact_page_skip(bm, session,
@@ -80,7 +80,7 @@ __compact_rewrite(WT_SESSION_IMPL *session, WT_REF *ref, bool *skipp)
if (mod->rec_result == WT_PM_REC_REPLACE ||
mod->rec_result == WT_PM_REC_MULTIBLOCK)
__wt_writeunlock(session, &page->page_lock);
WT_PAGE_UNLOCK(session, page);
return (ret);
}

View File

@@ -369,7 +369,7 @@ __cursor_col_modify(
WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, bool is_remove)
{
return (__wt_col_modify(session,
cbt, cbt->iface.recno, &cbt->iface.value, NULL, is_remove));
cbt, cbt->iface.recno, &cbt->iface.value, NULL, is_remove, false));
}
/*
@@ -381,7 +381,7 @@ __cursor_row_modify(
WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, bool is_remove)
{
return (__wt_row_modify(session,
cbt, &cbt->iface.key, &cbt->iface.value, NULL, is_remove));
cbt, &cbt->iface.key, &cbt->iface.value, NULL, is_remove, false));
}
/*

View File

@@ -689,8 +689,6 @@ __debug_page_metadata(WT_DBG *ds, WT_REF *ref)
WT_RET(ds->f(ds, ", entries %" PRIu32, entries));
WT_RET(ds->f(ds,
", %s", __wt_page_is_modified(page) ? "dirty" : "clean"));
WT_RET(ds->f(ds, ", %s", __wt_rwlock_islocked(
session, &page->page_lock) ? "locked" : "unlocked"));
if (F_ISSET_ATOMIC(page, WT_PAGE_BUILD_KEYS))
WT_RET(ds->f(ds, ", keys-built"));

View File

@@ -98,7 +98,6 @@ __page_out_int(WT_SESSION_IMPL *session, WT_PAGE **pagep, bool rewrite)
*/
WT_ASSERT(session, !__wt_page_is_modified(page));
WT_ASSERT(session, !F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU));
WT_ASSERT(session, !__wt_rwlock_islocked(session, &page->page_lock));
/*
* If a root page split, there may be one or more pages linked from the
@@ -254,6 +253,7 @@ __free_page_modify(WT_SESSION_IMPL *session, WT_PAGE *page)
__wt_ovfl_discard_free(session, page);
__wt_free(session, page->modify->ovfl_track);
__wt_spin_destroy(session, &page->modify->page_lock);
__wt_free(session, page->modify);
}

View File

@@ -444,7 +444,7 @@ __btree_conf(WT_SESSION_IMPL *session, WT_CKPT *ckpt)
}
/* Initialize locks. */
__wt_rwlock_init(session, &btree->ovfl_lock);
WT_RET(__wt_rwlock_init(session, &btree->ovfl_lock));
WT_RET(__wt_spin_init(session, &btree->flush_lock, "btree flush"));
btree->checkpointing = WT_CKPT_OFF; /* Not checkpointing */

View File

@@ -90,7 +90,7 @@ __col_instantiate(WT_SESSION_IMPL *session,
{
/* Search the page and add updates. */
WT_RET(__wt_col_search(session, recno, ref, cbt));
WT_RET(__wt_col_modify(session, cbt, recno, NULL, upd, false));
WT_RET(__wt_col_modify(session, cbt, recno, NULL, upd, false, false));
return (0);
}
@@ -104,7 +104,7 @@ __row_instantiate(WT_SESSION_IMPL *session,
{
/* Search the page and add updates. */
WT_RET(__wt_row_search(session, key, ref, cbt, true));
WT_RET(__wt_row_modify(session, cbt, key, NULL, upd, false));
WT_RET(__wt_row_modify(session, cbt, key, NULL, upd, false, false));
return (0);
}

View File

@@ -1256,12 +1256,12 @@ err: switch (complete) {
}
/*
* __split_internal_lock --
* __split_internal_lock_worker --
* Lock an internal page.
*/
static int
__split_internal_lock(WT_SESSION_IMPL *session, WT_REF *ref, bool trylock,
WT_PAGE **parentp, bool *hazardp)
__split_internal_lock_worker(WT_SESSION_IMPL *session,
WT_REF *ref, bool trylock, WT_PAGE **parentp, bool *hazardp)
{
WT_DECL_RET;
WT_PAGE *parent;
@@ -1300,13 +1300,19 @@ __split_internal_lock(WT_SESSION_IMPL *session, WT_REF *ref, bool trylock,
for (;;) {
parent = ref->home;
/*
* The page will be marked dirty, and we can only lock a page
* with a modify structure.
*/
WT_RET(__wt_page_modify_init(session, parent));
if (trylock)
WT_RET(__wt_try_writelock(session, &parent->page_lock));
WT_RET(WT_PAGE_TRYLOCK(session, parent));
else
__wt_writelock(session, &parent->page_lock);
WT_PAGE_LOCK(session, parent);
if (parent == ref->home)
break;
__wt_writeunlock(session, &parent->page_lock);
WT_PAGE_UNLOCK(session, parent);
}
/*
@@ -1329,7 +1335,33 @@ __split_internal_lock(WT_SESSION_IMPL *session, WT_REF *ref, bool trylock,
*parentp = parent;
return (0);
err: __wt_writeunlock(session, &parent->page_lock);
err: WT_PAGE_UNLOCK(session, parent);
return (ret);
}
/*
* __split_internal_lock --
* Lock an internal page.
*/
static int
__split_internal_lock(WT_SESSION_IMPL *session,
WT_REF *ref, bool trylock, WT_PAGE **parentp, bool *hazardp)
{
WT_DECL_RET;
/*
* There's no lock on our parent page and we're about to acquire one,
* which implies using the WT_REF.home field to reference our parent
* page. As a child of the parent page, we prevent its eviction, but
* that's a weak guarantee. If the parent page splits, and our WT_REF
* were to move with the split, the WT_REF.home field might change
* underneath us and we could race, and end up attempting to access
* an evicted page. Set the session page-index generation so if the
* parent splits, it still can't be evicted.
*/
WT_WITH_PAGE_INDEX(session,
ret = __split_internal_lock_worker(
session, ref, trylock, parentp, hazardp));
return (ret);
}
@@ -1345,7 +1377,7 @@ __split_internal_unlock(WT_SESSION_IMPL *session, WT_PAGE *parent, bool hazard)
if (hazard)
ret = __wt_hazard_clear(session, parent->pg_intl_parent_ref);
__wt_writeunlock(session, &parent->page_lock);
WT_PAGE_UNLOCK(session, parent);
return (ret);
}
@@ -1559,7 +1591,7 @@ __split_multi_inmem(
/* Apply the modification. */
WT_ERR(__wt_col_modify(
session, &cbt, recno, NULL, upd, false));
session, &cbt, recno, NULL, upd, false, true));
break;
case WT_PAGE_ROW_LEAF:
/* Build a key. */
@@ -1581,7 +1613,7 @@ __split_multi_inmem(
/* Apply the modification. */
WT_ERR(__wt_row_modify(
session, &cbt, key, NULL, upd, false));
session, &cbt, key, NULL, upd, false, true));
break;
WT_ILLEGAL_VALUE_ERR(session);
}

View File

@@ -17,7 +17,8 @@ static int __col_insert_alloc(
*/
int
__wt_col_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
uint64_t recno, WT_ITEM *value, WT_UPDATE *upd_arg, bool is_remove)
uint64_t recno, WT_ITEM *value,
WT_UPDATE *upd_arg, bool is_remove, bool exclusive)
{
WT_BTREE *btree;
WT_DECL_RET;
@@ -103,7 +104,7 @@ __wt_col_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
/* Serialize the update. */
WT_ERR(__wt_update_serial(
session, page, &cbt->ins->upd, &upd, upd_size));
session, page, &cbt->ins->upd, &upd, upd_size, false));
} else {
/* Allocate the append/update list reference as necessary. */
if (append) {
@@ -185,11 +186,11 @@ __wt_col_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
if (append)
WT_ERR(__wt_col_append_serial(
session, page, cbt->ins_head, cbt->ins_stack,
&ins, ins_size, &cbt->recno, skipdepth));
&ins, ins_size, &cbt->recno, skipdepth, exclusive));
else
WT_ERR(__wt_insert_serial(
session, page, cbt->ins_head, cbt->ins_stack,
&ins, ins_size, skipdepth));
&ins, ins_size, skipdepth, exclusive));
}
/* If the update was successful, add it to the in-memory log. */

View File

@@ -471,6 +471,8 @@ __wt_row_ikey_alloc(WT_SESSION_IMPL *session,
{
WT_IKEY *ikey;
WT_ASSERT(session, key != NULL); /* quiet clang scan-build */
/*
* Allocate memory for the WT_IKEY structure and the key, then copy
* the key into place.

View File

@@ -15,18 +15,13 @@
int
__wt_page_modify_alloc(WT_SESSION_IMPL *session, WT_PAGE *page)
{
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_PAGE_MODIFY *modify;
conn = S2C(session);
WT_RET(__wt_calloc_one(session, &modify));
/*
* Select a spinlock for the page; let the barrier immediately below
* keep things from racing too badly.
*/
modify->page_lock = ++conn->page_lock_cnt % WT_PAGE_LOCKS;
/* Initialize the spinlock for the page. */
WT_ERR(__wt_spin_init(session, &modify->page_lock, "btree page"));
/*
* Multiple threads of control may be searching and deciding to modify
@@ -37,8 +32,8 @@ __wt_page_modify_alloc(WT_SESSION_IMPL *session, WT_PAGE *page)
if (__wt_atomic_cas_ptr(&page->modify, NULL, modify))
__wt_cache_page_inmem_incr(session, page, sizeof(*modify));
else
__wt_free(session, modify);
return (0);
err: __wt_free(session, modify);
return (ret);
}
/*
@@ -47,7 +42,8 @@ __wt_page_modify_alloc(WT_SESSION_IMPL *session, WT_PAGE *page)
*/
int
__wt_row_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
WT_ITEM *key, WT_ITEM *value, WT_UPDATE *upd_arg, bool is_remove)
WT_ITEM *key, WT_ITEM *value,
WT_UPDATE *upd_arg, bool is_remove, bool exclusive)
{
WT_DECL_RET;
WT_INSERT *ins;
@@ -132,7 +128,7 @@ __wt_row_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
/* Serialize the update. */
WT_ERR(__wt_update_serial(
session, page, upd_entry, &upd, upd_size));
session, page, upd_entry, &upd, upd_size, exclusive));
} else {
/*
* Allocate the insert array as necessary.
@@ -207,7 +203,7 @@ __wt_row_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
/* Insert the WT_INSERT structure. */
WT_ERR(__wt_insert_serial(
session, page, cbt->ins_head, cbt->ins_stack,
&ins, ins_size, skipdepth));
&ins, ins_size, skipdepth, exclusive));
}
if (logged)

View File

@@ -312,7 +312,7 @@ __wt_cache_destroy(WT_SESSION_IMPL *session)
cache->bytes_dirty_intl + cache->bytes_dirty_leaf,
cache->pages_dirty_intl + cache->pages_dirty_leaf);
WT_TRET(__wt_cond_destroy(session, &cache->evict_cond));
__wt_cond_destroy(session, &cache->evict_cond);
__wt_spin_destroy(session, &cache->evict_pass_lock);
__wt_spin_destroy(session, &cache->evict_queue_lock);
__wt_spin_destroy(session, &cache->evict_walk_lock);

View File

@@ -225,7 +225,7 @@ err: __wt_spin_unlock(session, &__wt_process.spinlock);
__wt_free(session, pool_name);
if (ret != 0 && created) {
__wt_free(session, cp->name);
WT_TRET(__wt_cond_destroy(session, &cp->cache_pool_cond));
__wt_cond_destroy(session, &cp->cache_pool_cond);
__wt_free(session, cp);
}
return (ret);
@@ -391,7 +391,7 @@ __wt_conn_cache_pool_destroy(WT_SESSION_IMPL *session)
__wt_free(session, cp->name);
__wt_spin_destroy(session, &cp->cache_pool_lock);
WT_TRET(__wt_cond_destroy(session, &cp->cache_pool_cond));
__wt_cond_destroy(session, &cp->cache_pool_cond);
__wt_free(session, cp);
}

View File

@@ -231,7 +231,7 @@ __wt_checkpoint_server_destroy(WT_SESSION_IMPL *session)
WT_TRET(__wt_thread_join(session, conn->ckpt_tid));
conn->ckpt_tid_set = false;
}
WT_TRET(__wt_cond_destroy(session, &conn->ckpt_cond));
__wt_cond_destroy(session, &conn->ckpt_cond);
/* Close the server thread's session. */
if (conn->ckpt_session != NULL) {

View File

@@ -52,7 +52,7 @@ __wt_conn_dhandle_alloc(
WT_RET(__wt_calloc_one(session, &dhandle));
__wt_rwlock_init(session, &dhandle->rwlock);
WT_ERR(__wt_rwlock_init(session, &dhandle->rwlock));
dhandle->name_hash = __wt_hash_city64(uri, strlen(uri));
WT_ERR(__wt_strdup(session, uri, &dhandle->name));
WT_ERR(__wt_strdup(session, checkpoint, &dhandle->checkpoint));
@@ -475,6 +475,49 @@ err: WT_DHANDLE_RELEASE(dhandle);
return (ret);
}
/*
* __conn_dhandle_close_one --
* Lock and, if necessary, close a data handle.
*/
static int
__conn_dhandle_close_one(WT_SESSION_IMPL *session,
const char *uri, const char *checkpoint, bool force)
{
WT_DECL_RET;
/*
* Lock the handle exclusively. If this is part of schema-changing
* operation (indicated by metadata tracking being enabled), hold the
* lock for the duration of the operation.
*/
WT_RET(__wt_session_get_btree(session, uri, checkpoint,
NULL, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_LOCK_ONLY));
if (WT_META_TRACKING(session))
WT_RET(__wt_meta_track_handle_lock(session, false));
/*
* We have an exclusive lock, which means there are no cursors open at
* this point. Close the handle, if necessary.
*/
if (F_ISSET(session->dhandle, WT_DHANDLE_OPEN)) {
__wt_meta_track_sub_on(session);
ret = __wt_conn_btree_sync_and_close(session, false, force);
/*
* If the close succeeded, drop any locks it acquired. If
* there was a failure, this function will fail and the whole
* transaction will be rolled back.
*/
if (ret == 0)
ret = __wt_meta_track_sub_off(session);
}
if (!WT_META_TRACKING(session))
WT_TRET(__wt_session_release_btree(session));
return (ret);
}
/*
* __wt_conn_dhandle_close_all --
* Close all data handles handles with matching name (including all
@@ -495,48 +538,22 @@ __wt_conn_dhandle_close_all(
F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST_WRITE));
WT_ASSERT(session, session->dhandle == NULL);
/*
* Lock the live handle first. This ordering is important: we rely on
* locking the live handle to fail fast if the tree is busy (e.g., with
* cursors open or in a checkpoint).
*/
WT_ERR(__conn_dhandle_close_one(session, uri, NULL, force));
bucket = __wt_hash_city64(uri, strlen(uri)) % WT_HASH_ARRAY_SIZE;
TAILQ_FOREACH(dhandle, &conn->dhhash[bucket], hashq) {
if (strcmp(dhandle->name, uri) != 0 ||
dhandle->checkpoint == NULL ||
F_ISSET(dhandle, WT_DHANDLE_DEAD))
continue;
session->dhandle = dhandle;
/*
* Lock the handle exclusively. If this is part of
* schema-changing operation (indicated by metadata tracking
* being enabled), hold the lock for the duration of the
* operation.
*/
WT_ERR(__wt_session_get_btree(session,
dhandle->name, dhandle->checkpoint,
NULL, WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_LOCK_ONLY));
if (WT_META_TRACKING(session))
WT_ERR(__wt_meta_track_handle_lock(session, false));
/*
* We have an exclusive lock, which means there are no cursors
* open at this point. Close the handle, if necessary.
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
__wt_meta_track_sub_on(session);
ret = __wt_conn_btree_sync_and_close(
session, false, force);
/*
* If the close succeeded, drop any locks it acquired.
* If there was a failure, this function will fail and
* the whole transaction will be rolled back.
*/
if (ret == 0)
ret = __wt_meta_track_sub_off(session);
}
if (!WT_META_TRACKING(session))
WT_TRET(__wt_session_release_btree(session));
WT_ERR(ret);
WT_ERR(__conn_dhandle_close_one(
session, dhandle->name, dhandle->checkpoint, force));
}
err: session->dhandle = NULL;

View File

@@ -62,14 +62,9 @@ __wt_connection_init(WT_CONNECTION_IMPL *conn)
WT_RET(__wt_spin_init(session, &conn->turtle_lock, "turtle file"));
/* Read-write locks */
__wt_rwlock_init(session, &conn->dhandle_lock);
__wt_rwlock_init(session, &conn->hot_backup_lock);
__wt_rwlock_init(session, &conn->table_lock);
WT_RET(__wt_calloc_def(session, WT_PAGE_LOCKS, &conn->page_lock));
for (i = 0; i < WT_PAGE_LOCKS; ++i)
WT_RET(
__wt_spin_init(session, &conn->page_lock[i], "btree page"));
WT_RET(__wt_rwlock_init(session, &conn->dhandle_lock));
WT_RET(__wt_rwlock_init(session, &conn->hot_backup_lock));
WT_RET(__wt_rwlock_init(session, &conn->table_lock));
/* Setup the spin locks for the LSM manager queues. */
WT_RET(__wt_spin_init(session,
@@ -113,7 +108,6 @@ void
__wt_connection_destroy(WT_CONNECTION_IMPL *conn)
{
WT_SESSION_IMPL *session;
u_int i;
/* Check there's something to destroy. */
if (conn == NULL)
@@ -144,9 +138,6 @@ __wt_connection_destroy(WT_CONNECTION_IMPL *conn)
__wt_spin_destroy(session, &conn->schema_lock);
__wt_rwlock_destroy(session, &conn->table_lock);
__wt_spin_destroy(session, &conn->turtle_lock);
for (i = 0; i < WT_PAGE_LOCKS; ++i)
__wt_spin_destroy(session, &conn->page_lock[i]);
__wt_free(session, conn->page_lock);
/* Free allocated memory. */
__wt_free(session, conn->cfg);

View File

@@ -880,7 +880,7 @@ __wt_logmgr_create(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_spin_init(session, &log->log_sync_lock, "log sync"));
WT_RET(__wt_spin_init(session, &log->log_writelsn_lock,
"log write LSN"));
__wt_rwlock_init(session, &log->log_archive_lock);
WT_RET(__wt_rwlock_init(session, &log->log_archive_lock));
if (FLD_ISSET(conn->direct_io, WT_DIRECT_IO_LOG))
log->allocsize = (uint32_t)
WT_MAX(conn->buffer_alignment, WT_LOG_ALIGN);
@@ -1043,12 +1043,12 @@ __wt_logmgr_destroy(WT_SESSION_IMPL *session)
}
/* Destroy the condition variables now that all threads are stopped */
WT_TRET(__wt_cond_destroy(session, &conn->log_cond));
WT_TRET(__wt_cond_destroy(session, &conn->log_file_cond));
WT_TRET(__wt_cond_destroy(session, &conn->log_wrlsn_cond));
__wt_cond_destroy(session, &conn->log_cond);
__wt_cond_destroy(session, &conn->log_file_cond);
__wt_cond_destroy(session, &conn->log_wrlsn_cond);
WT_TRET(__wt_cond_destroy(session, &conn->log->log_sync_cond));
WT_TRET(__wt_cond_destroy(session, &conn->log->log_write_cond));
__wt_cond_destroy(session, &conn->log->log_sync_cond);
__wt_cond_destroy(session, &conn->log->log_write_cond);
__wt_rwlock_destroy(session, &conn->log->log_archive_lock);
__wt_spin_destroy(session, &conn->log->log_lock);
__wt_spin_destroy(session, &conn->log->log_slot_lock);

View File

@@ -648,7 +648,7 @@ __wt_statlog_destroy(WT_SESSION_IMPL *session, bool is_close)
WT_TRET(__wt_thread_join(session, conn->stat_tid));
conn->stat_tid_set = false;
}
WT_TRET(__wt_cond_destroy(session, &conn->stat_cond));
__wt_cond_destroy(session, &conn->stat_cond);
/* Log a set of statistics on shutdown if configured. */
if (is_close)

View File

@@ -432,7 +432,7 @@ __wt_sweep_destroy(WT_SESSION_IMPL *session)
WT_TRET(__wt_thread_join(session, conn->sweep_tid));
conn->sweep_tid_set = 0;
}
WT_TRET(__wt_cond_destroy(session, &conn->sweep_cond));
__wt_cond_destroy(session, &conn->sweep_cond);
if (conn->sweep_session != NULL) {
wt_session = &conn->sweep_session->iface;

View File

@@ -486,7 +486,14 @@ __curfile_create(WT_SESSION_IMPL *session,
WT_STAT_DATA_INCR(session, cursor_create);
if (0) {
err: WT_TRET(__curfile_close(cursor));
err: /*
* Our caller expects to release the data handle if we fail.
* Disconnect it from the cursor before closing.
*/
if (session->dhandle != NULL)
__wt_cursor_dhandle_decr_use(session);
cbt->btree = NULL;
WT_TRET(__curfile_close(cursor));
*cursorp = NULL;
}

View File

@@ -943,6 +943,12 @@ __wt_curtable_open(WT_SESSION_IMPL *session,
table->cgroups[0]->source, NULL, cfg, cursorp);
__wt_schema_release_table(session, table);
if (ret == 0) {
/* Fix up the public URI to match what was passed in. */
cursor = *cursorp;
__wt_free(session, cursor->uri);
WT_TRET(__wt_strdup(session, uri, &cursor->uri));
}
return (ret);
}

View File

@@ -65,19 +65,20 @@ each of which is ordered by one or more columns.
- @subpage_single wtperf
- @subpage_single wtstats
<p>
- @subpage_single tune_memory_allocator
- @subpage_single tune_page_size_and_comp
- @subpage_single tune_cache
- @subpage_single tune_build_options
- @subpage_single tune_bulk_load
- @subpage_single tune_cursor_persist
- @subpage_single tune_read_only
- @subpage_single tune_durability
- @subpage_single tune_cache
- @subpage_single tune_checksum
- @subpage_single tune_close
- @subpage_single tune_cursor_persist
- @subpage_single tune_durability
- @subpage_single tune_file_alloc
- @subpage_single tune_memory_allocator
- @subpage_single tune_mutex
- @subpage_single tune_page_size_and_comp
- @subpage_single tune_read_only
- @subpage_single tune_system_buffer_cache
- @subpage_single tune_transparent_huge_pages
- @subpage_single tune_close
- @subpage_single tune_mutex
- @subpage_single tune_zone_reclaim
*/

View File

@@ -237,6 +237,7 @@ fput
freelist
fsync
ftruncate
fvisibility
gcc
gdbm
ge

View File

@@ -0,0 +1,9 @@
/*! @page tune_build_options gcc/clang build options
WiredTiger can be built using the gcc/clang \c -fvisibility=hidden flag,
which may significantly reduce the size and load time of the WiredTiger
library when built as a dynamic shared object, and allow the optimizer
to produce better code (for example, by eliminating most lookups in the
procedure linkage table).
*/

View File

@@ -414,18 +414,20 @@ struct __wt_page_modify {
size_t discard_allocated;
} *ovfl_track;
#define WT_PAGE_LOCK(s, p) \
__wt_spin_lock((s), &(p)->modify->page_lock)
#define WT_PAGE_TRYLOCK(s, p) \
__wt_spin_trylock((s), &(p)->modify->page_lock)
#define WT_PAGE_UNLOCK(s, p) \
__wt_spin_unlock((s), &(p)->modify->page_lock)
WT_SPINLOCK page_lock; /* Page's spinlock */
/*
* The write generation is incremented when a page is modified, a page
* is clean if the write generation is 0.
*/
uint32_t write_gen;
#define WT_PAGE_LOCK(s, p) \
__wt_spin_lock((s), &S2C(s)->page_lock[(p)->modify->page_lock])
#define WT_PAGE_UNLOCK(s, p) \
__wt_spin_unlock((s), &S2C(s)->page_lock[(p)->modify->page_lock])
uint8_t page_lock; /* Page's spinlock */
#define WT_PM_REC_EMPTY 1 /* Reconciliation: no replacement */
#define WT_PM_REC_MULTIBLOCK 2 /* Reconciliation: multiple blocks */
#define WT_PM_REC_REPLACE 3 /* Reconciliation: single block */
@@ -602,13 +604,6 @@ struct __wt_page {
uint8_t unused[2]; /* Unused padding */
/*
* Used to protect and co-ordinate splits for internal pages and
* reconciliation for all pages. Only used to co-ordinate among the
* uncommon cases that require exclusive access to a page.
*/
WT_RWLOCK page_lock;
/*
* The page's read generation acts as an LRU value for each page in the
* tree; it is used by the eviction server thread to select pages to be
@@ -635,8 +630,6 @@ struct __wt_page {
#define WT_READGEN_STEP 100
uint64_t read_gen;
uint64_t evict_pass_gen; /* Eviction pass generation */
size_t memory_footprint; /* Memory attached to the page */
/* Page's on-disk representation: NULL for pages created in memory. */
@@ -644,6 +637,10 @@ struct __wt_page {
/* If/when the page is modified, we need lots more information. */
WT_PAGE_MODIFY *modify;
/* This is the 64 byte boundary, try to keep hot fields above here. */
uint64_t evict_pass_gen; /* Eviction pass generation */
};
/*

View File

@@ -175,21 +175,6 @@ struct __wt_connection_impl {
WT_SPINLOCK turtle_lock; /* Turtle file spinlock */
WT_RWLOCK dhandle_lock; /* Data handle list lock */
/*
* We distribute the btree page locks across a set of spin locks. Don't
* use too many: they are only held for very short operations, each one
* is 64 bytes, so 256 will fill the L1 cache on most CPUs.
*
* Use a prime number of buckets rather than assuming a good hash
* (Reference Sedgewick, Algorithms in C, "Hash Functions").
*
* Note: this can't be an array, we impose cache-line alignment and gcc
* doesn't support that for arrays smaller than the alignment.
*/
#define WT_PAGE_LOCKS 17
WT_SPINLOCK *page_lock; /* Btree page spinlocks */
u_int page_lock_cnt; /* Next spinlock to use */
/* Connection queue */
TAILQ_ENTRY(__wt_connection_impl) q;
/* Cache pool queue */

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,32 @@
/* DO NOT EDIT: automatically built by dist/s_prototypes. */
extern int __wt_posix_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_directory_list_free(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, char **dirlist, uint32_t count) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, bool fail, void *sym_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_file_extend( WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_os_posix(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_directory_list_free(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, char **dirlist, uint32_t count) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, bool fail, void *sym_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_file_extend( WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_os_posix(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_getenv(WT_SESSION_IMPL *session, const char *variable, const char **envp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_map(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *mapped_regionp, size_t *lenp, void *mapped_cookiep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_map_preload(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, const void *map, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_map_discard(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *map, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_unmap(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *mapped_region, size_t len, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_once(void (*init_routine)(void)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_get_vm_pagesize(void) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern bool __wt_absolute_path(const char *path) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern const char *__wt_path_separator(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern bool __wt_has_priv(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_posix_map(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *mapped_regionp, size_t *lenp, void *mapped_cookiep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_map_preload(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, const void *map, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_map_discard(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *map, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_posix_unmap(WT_FILE_HANDLE *fh, WT_SESSION *wt_session, void *mapped_region, size_t len, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled);
extern void __wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond);
extern void __wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp);
extern int __wt_once(void (*init_routine)(void)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_get_vm_pagesize(void) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern bool __wt_absolute_path(const char *path);
extern const char *__wt_path_separator(void);
extern bool __wt_has_priv(void);
extern void __wt_stream_set_line_buffer(FILE *fp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern void __wt_stream_set_no_buffer(FILE *fp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern void __wt_sleep(uint64_t seconds, uint64_t micro_seconds) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern int __wt_vsnprintf_len_incr( char *buf, size_t size, size_t *retsizep, const char *fmt, va_list ap) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_id(char *buf, size_t buflen) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern void __wt_yield(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));

View File

@@ -1,35 +1,35 @@
/* DO NOT EDIT: automatically built by dist/s_prototypes. */
extern int __wt_win_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_win_directory_list_free(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, char **dirlist, uint32_t count) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, bool fail, void *sym_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_win_fs_size(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, wt_off_t *sizep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_os_win(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_getenv(WT_SESSION_IMPL *session, const char *variable, const char **envp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_win_map(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, void *mapped_regionp, size_t *lenp, void *mapped_cookiep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_win_unmap(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, void *mapped_region, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_once(void (*init_routine)(void)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_get_vm_pagesize(void) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern bool __wt_absolute_path(const char *path) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern const char *__wt_path_separator(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern bool __wt_has_priv(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_stream_set_line_buffer(FILE *fp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_stream_set_no_buffer(FILE *fp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_sleep(uint64_t seconds, uint64_t micro_seconds) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_vsnprintf_len_incr( char *buf, size_t size, size_t *retsizep, const char *fmt, va_list ap) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_id(char *buf, size_t buflen) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_to_utf16_string( WT_SESSION_IMPL *session, const char*utf8, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_to_utf8_string( WT_SESSION_IMPL *session, const wchar_t*wide, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern DWORD __wt_getlasterror(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_map_windows_error(DWORD windows_error) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern const char *__wt_formatmessage(WT_SESSION_IMPL *session, DWORD windows_error) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_yield(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_win_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_win_directory_list_free(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, char **dirlist, uint32_t count) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, bool fail, void *sym_ret) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_win_fs_size(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, wt_off_t *sizep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_os_win(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_getenv(WT_SESSION_IMPL *session, const char *variable, const char **envp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_win_map(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, void *mapped_regionp, size_t *lenp, void *mapped_cookiep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_win_unmap(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, void *mapped_region, size_t length, void *mapped_cookie) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled);
extern void __wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond);
extern void __wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp);
extern int __wt_once(void (*init_routine)(void)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_get_vm_pagesize(void) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern bool __wt_absolute_path(const char *path);
extern const char *__wt_path_separator(void);
extern bool __wt_has_priv(void);
extern void __wt_stream_set_line_buffer(FILE *fp);
extern void __wt_stream_set_no_buffer(FILE *fp);
extern void __wt_sleep(uint64_t seconds, uint64_t micro_seconds);
extern int __wt_vsnprintf_len_incr( char *buf, size_t size, size_t *retsizep, const char *fmt, va_list ap) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_id(char *buf, size_t buflen) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp);
extern int __wt_to_utf16_string( WT_SESSION_IMPL *session, const char*utf8, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_to_utf8_string( WT_SESSION_IMPL *session, const wchar_t*wide, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern DWORD __wt_getlasterror(void);
extern int __wt_map_windows_error(DWORD windows_error) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern const char *__wt_formatmessage(WT_SESSION_IMPL *session, DWORD windows_error);
extern void __wt_yield(void);

View File

@@ -9,7 +9,7 @@
#define WT_PTRDIFFT_FMT "td" /* ptrdiff_t format string */
#define WT_SIZET_FMT "zu" /* size_t format string */
/* Add GCC-specific attributes to types and function declarations. */
/* GCC-specific attributes. */
#define WT_PACKED_STRUCT_BEGIN(name) \
struct __attribute__ ((__packed__)) name {
#define WT_PACKED_STRUCT_END \

View File

@@ -9,6 +9,7 @@
#define WT_PTRDIFFT_FMT "td" /* ptrdiff_t format string */
#define WT_SIZET_FMT "zu" /* size_t format string */
/* Lint-specific attributes. */
#define WT_PACKED_STRUCT_BEGIN(name) \
struct name {
#define WT_PACKED_STRUCT_END \

View File

@@ -54,6 +54,31 @@ __wt_seconds(WT_SESSION_IMPL *session, time_t *timep)
*timep = t.tv_sec;
}
/*
* __wt_time_check_monotonic --
* Check and prevent time running backward. If we detect that it has, we
* set the time structure to the previous values, making time stand still
* until we see a time in the future of the highest value seen so far.
*/
static inline void
__wt_time_check_monotonic(WT_SESSION_IMPL *session, struct timespec *tsp)
{
/*
* Detect time going backward. If so, use the last
* saved timestamp.
*/
if (session == NULL)
return;
if (tsp->tv_sec < session->last_epoch.tv_sec ||
(tsp->tv_sec == session->last_epoch.tv_sec &&
tsp->tv_nsec < session->last_epoch.tv_nsec)) {
WT_STAT_CONN_INCR(session, time_travel);
*tsp = session->last_epoch;
} else
session->last_epoch = *tsp;
}
/*
* __wt_verbose --
* Verbose message.

View File

@@ -16,9 +16,7 @@
#define WT_PTRDIFFT_FMT "Id" /* ptrdiff_t format string */
#define WT_SIZET_FMT "Iu" /* size_t format string */
/*
* Add MSVC-specific attributes and pragmas to types and function declarations.
*/
/* MSVC-specific attributes. */
#define WT_PACKED_STRUCT_BEGIN(name) \
__pragma(pack(push,1)) \
struct name {

View File

@@ -37,17 +37,21 @@ struct __wt_condvar {
* Don't modify this structure without understanding the read/write locking
* functions.
*/
union __wt_rwlock { /* Read/write lock */
uint64_t u;
struct {
uint32_t wr; /* Writers and readers */
} i;
struct {
uint16_t writers; /* Now serving for writers */
uint16_t readers; /* Now serving for readers */
uint16_t next; /* Next available ticket number */
uint16_t writers_active;/* Count of active writers */
} s;
struct __wt_rwlock { /* Read/write lock */
volatile union {
uint64_t v; /* Full 64-bit value */
struct {
uint8_t current; /* Current ticket */
uint8_t next; /* Next available ticket */
uint8_t reader; /* Read queue ticket */
uint8_t __notused; /* Padding */
uint16_t readers_active;/* Count of active readers */
uint16_t readers_queued;/* Count of queued readers */
} s;
} u;
WT_CONDVAR *cond_readers; /* Blocking readers */
WT_CONDVAR *cond_writers; /* Blocking writers */
};
/*
@@ -63,8 +67,8 @@ union __wt_rwlock { /* Read/write lock */
#define SPINLOCK_PTHREAD_MUTEX_ADAPTIVE 3
struct __wt_spinlock {
WT_CACHE_LINE_PAD_BEGIN
#if SPINLOCK_TYPE == SPINLOCK_GCC
WT_CACHE_LINE_PAD_BEGIN
volatile int lock;
#elif SPINLOCK_TYPE == SPINLOCK_PTHREAD_MUTEX ||\
SPINLOCK_TYPE == SPINLOCK_PTHREAD_MUTEX_ADAPTIVE ||\
@@ -87,5 +91,8 @@ struct __wt_spinlock {
int16_t stat_int_usecs_off; /* waiting server threads offset */
int8_t initialized; /* Lock initialized, for cleanup */
#if SPINLOCK_TYPE == SPINLOCK_GCC
WT_CACHE_LINE_PAD_END
#endif
};

View File

@@ -154,7 +154,7 @@ __col_append_serial_func(WT_SESSION_IMPL *session, WT_INSERT_HEAD *ins_head,
static inline int
__wt_col_append_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
WT_INSERT_HEAD *ins_head, WT_INSERT ***ins_stack, WT_INSERT **new_insp,
size_t new_ins_size, uint64_t *recnop, u_int skipdepth)
size_t new_ins_size, uint64_t *recnop, u_int skipdepth, bool exclusive)
{
WT_INSERT *new_ins = *new_insp;
WT_DECL_RET;
@@ -165,11 +165,16 @@ __wt_col_append_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
/* Clear references to memory we now own and must free on error. */
*new_insp = NULL;
/* Acquire the page's spinlock, call the worker function. */
WT_PAGE_LOCK(session, page);
/*
* Acquire the page's spinlock unless we already have exclusive access.
* Then call the worker function.
*/
if (!exclusive)
WT_PAGE_LOCK(session, page);
ret = __col_append_serial_func(
session, ins_head, ins_stack, new_ins, recnop, skipdepth);
WT_PAGE_UNLOCK(session, page);
if (!exclusive)
WT_PAGE_UNLOCK(session, page);
if (ret != 0) {
/* Free unused memory on error. */
@@ -198,7 +203,7 @@ __wt_col_append_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
static inline int
__wt_insert_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
WT_INSERT_HEAD *ins_head, WT_INSERT ***ins_stack, WT_INSERT **new_insp,
size_t new_ins_size, u_int skipdepth)
size_t new_ins_size, u_int skipdepth, bool exclusive)
{
WT_INSERT *new_ins = *new_insp;
WT_DECL_RET;
@@ -220,10 +225,12 @@ __wt_insert_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
ret = __insert_simple_func(
session, ins_stack, new_ins, skipdepth);
else {
WT_PAGE_LOCK(session, page);
if (!exclusive)
WT_PAGE_LOCK(session, page);
ret = __insert_serial_func(
session, ins_head, ins_stack, new_ins, skipdepth);
WT_PAGE_UNLOCK(session, page);
if (!exclusive)
WT_PAGE_UNLOCK(session, page);
}
if (ret != 0) {
@@ -252,7 +259,8 @@ __wt_insert_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
*/
static inline int
__wt_update_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
WT_UPDATE **srch_upd, WT_UPDATE **updp, size_t upd_size)
WT_UPDATE **srch_upd, WT_UPDATE **updp, size_t upd_size,
bool exclusive)
{
WT_DECL_RET;
WT_UPDATE *obsolete, *upd = *updp;
@@ -295,7 +303,7 @@ __wt_update_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
/*
* If there are no subsequent WT_UPDATE structures we are done here.
*/
if (upd->next == NULL)
if (upd->next == NULL || exclusive)
return (0);
/*
@@ -316,11 +324,11 @@ __wt_update_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
}
/* If we can't lock it, don't scan, that's okay. */
if (__wt_try_writelock(session, &page->page_lock) != 0)
if (WT_PAGE_TRYLOCK(session, page) != 0)
return (0);
obsolete = __wt_update_obsolete_check(session, page, upd->next);
__wt_writeunlock(session, &page->page_lock);
WT_PAGE_UNLOCK(session, page);
if (obsolete != NULL)
__wt_update_obsolete_free(session, page, obsolete);

View File

@@ -66,6 +66,7 @@ struct __wt_session_impl {
/* Session handle reference list */
TAILQ_HEAD(__dhandles, __wt_data_handle_cache) dhandles;
time_t last_sweep; /* Last sweep for dead handles */
struct timespec last_epoch; /* Last epoch time returned */
/* Cursors closed with the session */
TAILQ_HEAD(__cursors, __wt_cursor) cursors;
@@ -97,6 +98,10 @@ struct __wt_session_impl {
*/
TAILQ_HEAD(__tables, __wt_table) tables;
/* Current rwlock for callback. */
WT_RWLOCK *current_rwlock;
uint8_t current_rwticket;
WT_ITEM **scratch; /* Temporary memory for any function */
u_int scratch_alloc; /* Currently allocated */
size_t scratch_cached; /* Scratch bytes cached */

View File

@@ -361,6 +361,7 @@ struct __wt_connection_stats {
int64_t cache_eviction_clean;
int64_t cond_auto_wait_reset;
int64_t cond_auto_wait;
int64_t time_travel;
int64_t file_open;
int64_t memory_allocation;
int64_t memory_free;

View File

@@ -59,7 +59,6 @@ __wt_verify_build(void)
sizeof(s) > WT_CACHE_LINE_ALIGNMENT || \
sizeof(s) % WT_CACHE_LINE_ALIGNMENT == 0)
WT_PADDING_CHECK(WT_LOGSLOT);
WT_PADDING_CHECK(WT_SPINLOCK);
WT_PADDING_CHECK(WT_TXN_STATE);
/*

View File

@@ -39,6 +39,16 @@ extern "C" {
#define __F(func) (*(func))
#endif
/*
* We support configuring WiredTiger with the gcc/clang -fvisibility=hidden
* flags, but that requires public APIs be specifically marked.
*/
#if defined(DOXYGEN) || defined(SWIG) || !defined(__GNUC__)
#define WT_ATTRIBUTE_LIBRARY_VISIBLE
#else
#define WT_ATTRIBUTE_LIBRARY_VISIBLE __attribute__((visibility("default")))
#endif
#ifdef SWIG
%{
#include <wiredtiger.h>
@@ -2553,7 +2563,7 @@ struct __wt_connection {
*/
int wiredtiger_open(const char *home,
WT_EVENT_HANDLER *errhandler, const char *config,
WT_CONNECTION **connectionp);
WT_CONNECTION **connectionp) WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Return information about a WiredTiger error as a string (see
@@ -2564,7 +2574,7 @@ int wiredtiger_open(const char *home,
* @param error a return value from a WiredTiger, ISO C, or POSIX standard API
* @returns a string representation of the error
*/
const char *wiredtiger_strerror(int error);
const char *wiredtiger_strerror(int error) WT_ATTRIBUTE_LIBRARY_VISIBLE;
#if !defined(SWIG)
/*!
@@ -2701,7 +2711,8 @@ struct __wt_event_handler {
* @errors
*/
int wiredtiger_struct_pack(WT_SESSION *session,
void *buffer, size_t size, const char *format, ...);
void *buffer, size_t size, const char *format, ...)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Calculate the size required to pack a structure.
@@ -2719,7 +2730,7 @@ int wiredtiger_struct_pack(WT_SESSION *session,
* @errors
*/
int wiredtiger_struct_size(WT_SESSION *session,
size_t *sizep, const char *format, ...);
size_t *sizep, const char *format, ...) WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Unpack a structure from a buffer.
@@ -2736,7 +2747,8 @@ int wiredtiger_struct_size(WT_SESSION *session,
* @errors
*/
int wiredtiger_struct_unpack(WT_SESSION *session,
const void *buffer, size_t size, const char *format, ...);
const void *buffer, size_t size, const char *format, ...)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
#if !defined(SWIG)
@@ -2763,7 +2775,8 @@ typedef struct __wt_pack_stream WT_PACK_STREAM;
* @errors
*/
int wiredtiger_pack_start(WT_SESSION *session,
const char *format, void *buffer, size_t size, WT_PACK_STREAM **psp);
const char *format, void *buffer, size_t size, WT_PACK_STREAM **psp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Start an unpacking operation from a buffer with the given format string.
@@ -2779,7 +2792,8 @@ int wiredtiger_pack_start(WT_SESSION *session,
* @errors
*/
int wiredtiger_unpack_start(WT_SESSION *session,
const char *format, const void *buffer, size_t size, WT_PACK_STREAM **psp);
const char *format, const void *buffer, size_t size, WT_PACK_STREAM **psp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Close a packing stream.
@@ -2788,7 +2802,8 @@ int wiredtiger_unpack_start(WT_SESSION *session,
* @param[out] usedp the number of bytes in the buffer used by the stream
* @errors
*/
int wiredtiger_pack_close(WT_PACK_STREAM *ps, size_t *usedp);
int wiredtiger_pack_close(WT_PACK_STREAM *ps, size_t *usedp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Pack an item into a packing stream.
@@ -2797,7 +2812,8 @@ int wiredtiger_pack_close(WT_PACK_STREAM *ps, size_t *usedp);
* @param item an item to pack
* @errors
*/
int wiredtiger_pack_item(WT_PACK_STREAM *ps, WT_ITEM *item);
int wiredtiger_pack_item(WT_PACK_STREAM *ps, WT_ITEM *item)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Pack a signed integer into a packing stream.
@@ -2806,7 +2822,8 @@ int wiredtiger_pack_item(WT_PACK_STREAM *ps, WT_ITEM *item);
* @param i a signed integer to pack
* @errors
*/
int wiredtiger_pack_int(WT_PACK_STREAM *ps, int64_t i);
int wiredtiger_pack_int(WT_PACK_STREAM *ps, int64_t i)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Pack a string into a packing stream.
@@ -2815,7 +2832,8 @@ int wiredtiger_pack_int(WT_PACK_STREAM *ps, int64_t i);
* @param s a string to pack
* @errors
*/
int wiredtiger_pack_str(WT_PACK_STREAM *ps, const char *s);
int wiredtiger_pack_str(WT_PACK_STREAM *ps, const char *s)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Pack an unsigned integer into a packing stream.
@@ -2824,7 +2842,8 @@ int wiredtiger_pack_str(WT_PACK_STREAM *ps, const char *s);
* @param u an unsigned integer to pack
* @errors
*/
int wiredtiger_pack_uint(WT_PACK_STREAM *ps, uint64_t u);
int wiredtiger_pack_uint(WT_PACK_STREAM *ps, uint64_t u)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Unpack an item from a packing stream.
@@ -2833,7 +2852,8 @@ int wiredtiger_pack_uint(WT_PACK_STREAM *ps, uint64_t u);
* @param item an item to unpack
* @errors
*/
int wiredtiger_unpack_item(WT_PACK_STREAM *ps, WT_ITEM *item);
int wiredtiger_unpack_item(WT_PACK_STREAM *ps, WT_ITEM *item)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Unpack a signed integer from a packing stream.
@@ -2842,7 +2862,8 @@ int wiredtiger_unpack_item(WT_PACK_STREAM *ps, WT_ITEM *item);
* @param[out] ip the unpacked signed integer
* @errors
*/
int wiredtiger_unpack_int(WT_PACK_STREAM *ps, int64_t *ip);
int wiredtiger_unpack_int(WT_PACK_STREAM *ps, int64_t *ip)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Unpack a string from a packing stream.
@@ -2851,7 +2872,8 @@ int wiredtiger_unpack_int(WT_PACK_STREAM *ps, int64_t *ip);
* @param[out] sp the unpacked string
* @errors
*/
int wiredtiger_unpack_str(WT_PACK_STREAM *ps, const char **sp);
int wiredtiger_unpack_str(WT_PACK_STREAM *ps, const char **sp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* Unpack an unsigned integer from a packing stream.
@@ -2860,7 +2882,8 @@ int wiredtiger_unpack_str(WT_PACK_STREAM *ps, const char **sp);
* @param[out] up the unpacked unsigned integer
* @errors
*/
int wiredtiger_unpack_uint(WT_PACK_STREAM *ps, uint64_t *up);
int wiredtiger_unpack_uint(WT_PACK_STREAM *ps, uint64_t *up)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*! @} */
/*!
@@ -2938,7 +2961,8 @@ struct __wt_config_item {
* @snippet ex_all.c Validate a configuration string
*/
int wiredtiger_config_validate(WT_SESSION *session,
WT_EVENT_HANDLER *errhandler, const char *name, const char *config);
WT_EVENT_HANDLER *errhandler, const char *name, const char *config)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
#endif
/*!
@@ -2958,7 +2982,8 @@ int wiredtiger_config_validate(WT_SESSION *session,
* @snippet ex_config_parse.c Create a configuration parser
*/
int wiredtiger_config_parser_open(WT_SESSION *session,
const char *config, size_t len, WT_CONFIG_PARSER **config_parserp);
const char *config, size_t len, WT_CONFIG_PARSER **config_parserp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*!
* A handle that can be used to search and traverse configuration strings
@@ -3047,7 +3072,8 @@ struct __wt_config_parser {
* @param patchp a location where the patch version number is returned
* @returns a string representation of the version
*/
const char *wiredtiger_version(int *majorp, int *minorp, int *patchp);
const char *wiredtiger_version(int *majorp, int *minorp, int *patchp)
WT_ATTRIBUTE_LIBRARY_VISIBLE;
/*******************************************
* Error returns
@@ -4546,304 +4572,306 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection);
#define WT_STAT_CONN_COND_AUTO_WAIT_RESET 1102
/*! connection: auto adjusting condition wait calls */
#define WT_STAT_CONN_COND_AUTO_WAIT 1103
/*! connection: detected system time went backwards */
#define WT_STAT_CONN_TIME_TRAVEL 1104
/*! connection: files currently open */
#define WT_STAT_CONN_FILE_OPEN 1104
#define WT_STAT_CONN_FILE_OPEN 1105
/*! connection: memory allocations */
#define WT_STAT_CONN_MEMORY_ALLOCATION 1105
#define WT_STAT_CONN_MEMORY_ALLOCATION 1106
/*! connection: memory frees */
#define WT_STAT_CONN_MEMORY_FREE 1106
#define WT_STAT_CONN_MEMORY_FREE 1107
/*! connection: memory re-allocations */
#define WT_STAT_CONN_MEMORY_GROW 1107
#define WT_STAT_CONN_MEMORY_GROW 1108
/*! connection: pthread mutex condition wait calls */
#define WT_STAT_CONN_COND_WAIT 1108
#define WT_STAT_CONN_COND_WAIT 1109
/*! connection: pthread mutex shared lock read-lock calls */
#define WT_STAT_CONN_RWLOCK_READ 1109
#define WT_STAT_CONN_RWLOCK_READ 1110
/*! connection: pthread mutex shared lock write-lock calls */
#define WT_STAT_CONN_RWLOCK_WRITE 1110
#define WT_STAT_CONN_RWLOCK_WRITE 1111
/*! connection: total fsync I/Os */
#define WT_STAT_CONN_FSYNC_IO 1111
#define WT_STAT_CONN_FSYNC_IO 1112
/*! connection: total read I/Os */
#define WT_STAT_CONN_READ_IO 1112
#define WT_STAT_CONN_READ_IO 1113
/*! connection: total write I/Os */
#define WT_STAT_CONN_WRITE_IO 1113
#define WT_STAT_CONN_WRITE_IO 1114
/*! cursor: cursor create calls */
#define WT_STAT_CONN_CURSOR_CREATE 1114
#define WT_STAT_CONN_CURSOR_CREATE 1115
/*! cursor: cursor insert calls */
#define WT_STAT_CONN_CURSOR_INSERT 1115
#define WT_STAT_CONN_CURSOR_INSERT 1116
/*! cursor: cursor next calls */
#define WT_STAT_CONN_CURSOR_NEXT 1116
#define WT_STAT_CONN_CURSOR_NEXT 1117
/*! cursor: cursor prev calls */
#define WT_STAT_CONN_CURSOR_PREV 1117
#define WT_STAT_CONN_CURSOR_PREV 1118
/*! cursor: cursor remove calls */
#define WT_STAT_CONN_CURSOR_REMOVE 1118
#define WT_STAT_CONN_CURSOR_REMOVE 1119
/*! cursor: cursor reset calls */
#define WT_STAT_CONN_CURSOR_RESET 1119
#define WT_STAT_CONN_CURSOR_RESET 1120
/*! cursor: cursor restarted searches */
#define WT_STAT_CONN_CURSOR_RESTART 1120
#define WT_STAT_CONN_CURSOR_RESTART 1121
/*! cursor: cursor search calls */
#define WT_STAT_CONN_CURSOR_SEARCH 1121
#define WT_STAT_CONN_CURSOR_SEARCH 1122
/*! cursor: cursor search near calls */
#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1122
#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1123
/*! cursor: cursor update calls */
#define WT_STAT_CONN_CURSOR_UPDATE 1123
#define WT_STAT_CONN_CURSOR_UPDATE 1124
/*! cursor: truncate calls */
#define WT_STAT_CONN_CURSOR_TRUNCATE 1124
#define WT_STAT_CONN_CURSOR_TRUNCATE 1125
/*! data-handle: connection data handles currently active */
#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1125
#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1126
/*! data-handle: connection sweep candidate became referenced */
#define WT_STAT_CONN_DH_SWEEP_REF 1126
#define WT_STAT_CONN_DH_SWEEP_REF 1127
/*! data-handle: connection sweep dhandles closed */
#define WT_STAT_CONN_DH_SWEEP_CLOSE 1127
#define WT_STAT_CONN_DH_SWEEP_CLOSE 1128
/*! data-handle: connection sweep dhandles removed from hash list */
#define WT_STAT_CONN_DH_SWEEP_REMOVE 1128
#define WT_STAT_CONN_DH_SWEEP_REMOVE 1129
/*! data-handle: connection sweep time-of-death sets */
#define WT_STAT_CONN_DH_SWEEP_TOD 1129
#define WT_STAT_CONN_DH_SWEEP_TOD 1130
/*! data-handle: connection sweeps */
#define WT_STAT_CONN_DH_SWEEPS 1130
#define WT_STAT_CONN_DH_SWEEPS 1131
/*! data-handle: session dhandles swept */
#define WT_STAT_CONN_DH_SESSION_HANDLES 1131
#define WT_STAT_CONN_DH_SESSION_HANDLES 1132
/*! data-handle: session sweep attempts */
#define WT_STAT_CONN_DH_SESSION_SWEEPS 1132
#define WT_STAT_CONN_DH_SESSION_SWEEPS 1133
/*! lock: checkpoint lock acquisitions */
#define WT_STAT_CONN_LOCK_CHECKPOINT_COUNT 1133
#define WT_STAT_CONN_LOCK_CHECKPOINT_COUNT 1134
/*! lock: checkpoint lock application thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_APPLICATION 1134
#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_APPLICATION 1135
/*! lock: checkpoint lock internal thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_INTERNAL 1135
#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_INTERNAL 1136
/*! lock: handle-list lock eviction thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_EVICTION 1136
#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_EVICTION 1137
/*! lock: metadata lock acquisitions */
#define WT_STAT_CONN_LOCK_METADATA_COUNT 1137
#define WT_STAT_CONN_LOCK_METADATA_COUNT 1138
/*! lock: metadata lock application thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_METADATA_WAIT_APPLICATION 1138
#define WT_STAT_CONN_LOCK_METADATA_WAIT_APPLICATION 1139
/*! lock: metadata lock internal thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_METADATA_WAIT_INTERNAL 1139
#define WT_STAT_CONN_LOCK_METADATA_WAIT_INTERNAL 1140
/*! lock: schema lock acquisitions */
#define WT_STAT_CONN_LOCK_SCHEMA_COUNT 1140
#define WT_STAT_CONN_LOCK_SCHEMA_COUNT 1141
/*! lock: schema lock application thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_APPLICATION 1141
#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_APPLICATION 1142
/*! lock: schema lock internal thread wait time (usecs) */
#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_INTERNAL 1142
#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_INTERNAL 1143
/*! lock: table lock acquisitions */
#define WT_STAT_CONN_LOCK_TABLE_COUNT 1143
#define WT_STAT_CONN_LOCK_TABLE_COUNT 1144
/*!
* lock: table lock application thread time waiting for the table lock
* (usecs)
*/
#define WT_STAT_CONN_LOCK_TABLE_WAIT_APPLICATION 1144
#define WT_STAT_CONN_LOCK_TABLE_WAIT_APPLICATION 1145
/*!
* lock: table lock internal thread time waiting for the table lock
* (usecs)
*/
#define WT_STAT_CONN_LOCK_TABLE_WAIT_INTERNAL 1145
#define WT_STAT_CONN_LOCK_TABLE_WAIT_INTERNAL 1146
/*! log: busy returns attempting to switch slots */
#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1146
#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1147
/*! log: consolidated slot closures */
#define WT_STAT_CONN_LOG_SLOT_CLOSES 1147
#define WT_STAT_CONN_LOG_SLOT_CLOSES 1148
/*! log: consolidated slot join active slot closed */
#define WT_STAT_CONN_LOG_SLOT_ACTIVE_CLOSED 1148
#define WT_STAT_CONN_LOG_SLOT_ACTIVE_CLOSED 1149
/*! log: consolidated slot join races */
#define WT_STAT_CONN_LOG_SLOT_RACES 1149
#define WT_STAT_CONN_LOG_SLOT_RACES 1150
/*! log: consolidated slot join transitions */
#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1150
#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1151
/*! log: consolidated slot joins */
#define WT_STAT_CONN_LOG_SLOT_JOINS 1151
#define WT_STAT_CONN_LOG_SLOT_JOINS 1152
/*! log: consolidated slot transitions unable to find free slot */
#define WT_STAT_CONN_LOG_SLOT_NO_FREE_SLOTS 1152
#define WT_STAT_CONN_LOG_SLOT_NO_FREE_SLOTS 1153
/*! log: consolidated slot unbuffered writes */
#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1153
#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1154
/*! log: log bytes of payload data */
#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1154
#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1155
/*! log: log bytes written */
#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1155
#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1156
/*! log: log files manually zero-filled */
#define WT_STAT_CONN_LOG_ZERO_FILLS 1156
#define WT_STAT_CONN_LOG_ZERO_FILLS 1157
/*! log: log flush operations */
#define WT_STAT_CONN_LOG_FLUSH 1157
#define WT_STAT_CONN_LOG_FLUSH 1158
/*! log: log force write operations */
#define WT_STAT_CONN_LOG_FORCE_WRITE 1158
#define WT_STAT_CONN_LOG_FORCE_WRITE 1159
/*! log: log force write operations skipped */
#define WT_STAT_CONN_LOG_FORCE_WRITE_SKIP 1159
#define WT_STAT_CONN_LOG_FORCE_WRITE_SKIP 1160
/*! log: log records compressed */
#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1160
#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1161
/*! log: log records not compressed */
#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1161
#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1162
/*! log: log records too small to compress */
#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1162
#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1163
/*! log: log release advances write LSN */
#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1163
#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1164
/*! log: log scan operations */
#define WT_STAT_CONN_LOG_SCANS 1164
#define WT_STAT_CONN_LOG_SCANS 1165
/*! log: log scan records requiring two reads */
#define WT_STAT_CONN_LOG_SCAN_REREADS 1165
#define WT_STAT_CONN_LOG_SCAN_REREADS 1166
/*! log: log server thread advances write LSN */
#define WT_STAT_CONN_LOG_WRITE_LSN 1166
#define WT_STAT_CONN_LOG_WRITE_LSN 1167
/*! log: log server thread write LSN walk skipped */
#define WT_STAT_CONN_LOG_WRITE_LSN_SKIP 1167
#define WT_STAT_CONN_LOG_WRITE_LSN_SKIP 1168
/*! log: log sync operations */
#define WT_STAT_CONN_LOG_SYNC 1168
#define WT_STAT_CONN_LOG_SYNC 1169
/*! log: log sync time duration (usecs) */
#define WT_STAT_CONN_LOG_SYNC_DURATION 1169
#define WT_STAT_CONN_LOG_SYNC_DURATION 1170
/*! log: log sync_dir operations */
#define WT_STAT_CONN_LOG_SYNC_DIR 1170
#define WT_STAT_CONN_LOG_SYNC_DIR 1171
/*! log: log sync_dir time duration (usecs) */
#define WT_STAT_CONN_LOG_SYNC_DIR_DURATION 1171
#define WT_STAT_CONN_LOG_SYNC_DIR_DURATION 1172
/*! log: log write operations */
#define WT_STAT_CONN_LOG_WRITES 1172
#define WT_STAT_CONN_LOG_WRITES 1173
/*! log: logging bytes consolidated */
#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1173
#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1174
/*! log: maximum log file size */
#define WT_STAT_CONN_LOG_MAX_FILESIZE 1174
#define WT_STAT_CONN_LOG_MAX_FILESIZE 1175
/*! log: number of pre-allocated log files to create */
#define WT_STAT_CONN_LOG_PREALLOC_MAX 1175
#define WT_STAT_CONN_LOG_PREALLOC_MAX 1176
/*! log: pre-allocated log files not ready and missed */
#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1176
#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1177
/*! log: pre-allocated log files prepared */
#define WT_STAT_CONN_LOG_PREALLOC_FILES 1177
#define WT_STAT_CONN_LOG_PREALLOC_FILES 1178
/*! log: pre-allocated log files used */
#define WT_STAT_CONN_LOG_PREALLOC_USED 1178
#define WT_STAT_CONN_LOG_PREALLOC_USED 1179
/*! log: records processed by log scan */
#define WT_STAT_CONN_LOG_SCAN_RECORDS 1179
#define WT_STAT_CONN_LOG_SCAN_RECORDS 1180
/*! log: total in-memory size of compressed records */
#define WT_STAT_CONN_LOG_COMPRESS_MEM 1180
#define WT_STAT_CONN_LOG_COMPRESS_MEM 1181
/*! log: total log buffer size */
#define WT_STAT_CONN_LOG_BUFFER_SIZE 1181
#define WT_STAT_CONN_LOG_BUFFER_SIZE 1182
/*! log: total size of compressed records */
#define WT_STAT_CONN_LOG_COMPRESS_LEN 1182
#define WT_STAT_CONN_LOG_COMPRESS_LEN 1183
/*! log: written slots coalesced */
#define WT_STAT_CONN_LOG_SLOT_COALESCED 1183
#define WT_STAT_CONN_LOG_SLOT_COALESCED 1184
/*! log: yields waiting for previous log file close */
#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1184
#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1185
/*! reconciliation: fast-path pages deleted */
#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1185
#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1186
/*! reconciliation: page reconciliation calls */
#define WT_STAT_CONN_REC_PAGES 1186
#define WT_STAT_CONN_REC_PAGES 1187
/*! reconciliation: page reconciliation calls for eviction */
#define WT_STAT_CONN_REC_PAGES_EVICTION 1187
#define WT_STAT_CONN_REC_PAGES_EVICTION 1188
/*! reconciliation: pages deleted */
#define WT_STAT_CONN_REC_PAGE_DELETE 1188
#define WT_STAT_CONN_REC_PAGE_DELETE 1189
/*! reconciliation: split bytes currently awaiting free */
#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1189
#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1190
/*! reconciliation: split objects currently awaiting free */
#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1190
#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1191
/*! session: open cursor count */
#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1191
#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1192
/*! session: open session count */
#define WT_STAT_CONN_SESSION_OPEN 1192
#define WT_STAT_CONN_SESSION_OPEN 1193
/*! session: table alter failed calls */
#define WT_STAT_CONN_SESSION_TABLE_ALTER_FAIL 1193
#define WT_STAT_CONN_SESSION_TABLE_ALTER_FAIL 1194
/*! session: table alter successful calls */
#define WT_STAT_CONN_SESSION_TABLE_ALTER_SUCCESS 1194
#define WT_STAT_CONN_SESSION_TABLE_ALTER_SUCCESS 1195
/*! session: table alter unchanged and skipped */
#define WT_STAT_CONN_SESSION_TABLE_ALTER_SKIP 1195
#define WT_STAT_CONN_SESSION_TABLE_ALTER_SKIP 1196
/*! session: table compact failed calls */
#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1196
#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1197
/*! session: table compact successful calls */
#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1197
#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1198
/*! session: table create failed calls */
#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1198
#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1199
/*! session: table create successful calls */
#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1199
#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1200
/*! session: table drop failed calls */
#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1200
#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1201
/*! session: table drop successful calls */
#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1201
#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1202
/*! session: table rebalance failed calls */
#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1202
#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1203
/*! session: table rebalance successful calls */
#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1203
#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1204
/*! session: table rename failed calls */
#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1204
#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1205
/*! session: table rename successful calls */
#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1205
#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1206
/*! session: table salvage failed calls */
#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1206
#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1207
/*! session: table salvage successful calls */
#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1207
#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1208
/*! session: table truncate failed calls */
#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1208
#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1209
/*! session: table truncate successful calls */
#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1209
#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1210
/*! session: table verify failed calls */
#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1210
#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1211
/*! session: table verify successful calls */
#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1211
#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1212
/*! thread-state: active filesystem fsync calls */
#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1212
#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1213
/*! thread-state: active filesystem read calls */
#define WT_STAT_CONN_THREAD_READ_ACTIVE 1213
#define WT_STAT_CONN_THREAD_READ_ACTIVE 1214
/*! thread-state: active filesystem write calls */
#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1214
#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1215
/*! thread-yield: application thread time evicting (usecs) */
#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1215
#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1216
/*! thread-yield: application thread time waiting for cache (usecs) */
#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1216
#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1217
/*! thread-yield: page acquire busy blocked */
#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1217
#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1218
/*! thread-yield: page acquire eviction blocked */
#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1218
#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1219
/*! thread-yield: page acquire locked blocked */
#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1219
#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1220
/*! thread-yield: page acquire read blocked */
#define WT_STAT_CONN_PAGE_READ_BLOCKED 1220
#define WT_STAT_CONN_PAGE_READ_BLOCKED 1221
/*! thread-yield: page acquire time sleeping (usecs) */
#define WT_STAT_CONN_PAGE_SLEEP 1221
#define WT_STAT_CONN_PAGE_SLEEP 1222
/*! transaction: number of named snapshots created */
#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1222
#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1223
/*! transaction: number of named snapshots dropped */
#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1223
#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1224
/*! transaction: transaction begins */
#define WT_STAT_CONN_TXN_BEGIN 1224
#define WT_STAT_CONN_TXN_BEGIN 1225
/*! transaction: transaction checkpoint currently running */
#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1225
#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1226
/*! transaction: transaction checkpoint generation */
#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1226
#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1227
/*! transaction: transaction checkpoint max time (msecs) */
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1227
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1228
/*! transaction: transaction checkpoint min time (msecs) */
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1228
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1229
/*! transaction: transaction checkpoint most recent time (msecs) */
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1229
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1230
/*! transaction: transaction checkpoint scrub dirty target */
#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1230
#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1231
/*! transaction: transaction checkpoint scrub time (msecs) */
#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1231
#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1232
/*! transaction: transaction checkpoint total time (msecs) */
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1232
#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1233
/*! transaction: transaction checkpoints */
#define WT_STAT_CONN_TXN_CHECKPOINT 1233
#define WT_STAT_CONN_TXN_CHECKPOINT 1234
/*!
* transaction: transaction checkpoints skipped because database was
* clean
*/
#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1234
#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1235
/*! transaction: transaction failures due to cache overflow */
#define WT_STAT_CONN_TXN_FAIL_CACHE 1235
#define WT_STAT_CONN_TXN_FAIL_CACHE 1236
/*!
* transaction: transaction fsync calls for checkpoint after allocating
* the transaction ID
*/
#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1236
#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1237
/*!
* transaction: transaction fsync duration for checkpoint after
* allocating the transaction ID (usecs)
*/
#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1237
#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1238
/*! transaction: transaction range of IDs currently pinned */
#define WT_STAT_CONN_TXN_PINNED_RANGE 1238
#define WT_STAT_CONN_TXN_PINNED_RANGE 1239
/*! transaction: transaction range of IDs currently pinned by a checkpoint */
#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1239
#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1240
/*!
* transaction: transaction range of IDs currently pinned by named
* snapshots
*/
#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1240
#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1241
/*! transaction: transaction sync calls */
#define WT_STAT_CONN_TXN_SYNC 1241
#define WT_STAT_CONN_TXN_SYNC 1242
/*! transaction: transactions committed */
#define WT_STAT_CONN_TXN_COMMIT 1242
#define WT_STAT_CONN_TXN_COMMIT 1243
/*! transaction: transactions rolled back */
#define WT_STAT_CONN_TXN_ROLLBACK 1243
#define WT_STAT_CONN_TXN_ROLLBACK 1244
/*!
* @}

View File

@@ -268,6 +268,8 @@ struct __wt_ref;
typedef struct __wt_ref WT_REF;
struct __wt_row;
typedef struct __wt_row WT_ROW;
struct __wt_rwlock;
typedef struct __wt_rwlock WT_RWLOCK;
struct __wt_salvage_cookie;
typedef struct __wt_salvage_cookie WT_SALVAGE_COOKIE;
struct __wt_save_upd;
@@ -302,8 +304,6 @@ union __wt_lsn;
typedef union __wt_lsn WT_LSN;
union __wt_rand_state;
typedef union __wt_rand_state WT_RAND_STATE;
union __wt_rwlock;
typedef union __wt_rwlock WT_RWLOCK;
/*
* Forward type declarations for internal types: END
* DO NOT EDIT: automatically built by dist/s_typedef.

View File

@@ -1661,8 +1661,6 @@ __wt_clsm_close(WT_CURSOR *cursor)
/* In case we were somehow left positioned, clear that. */
__clsm_leave(clsm);
/* The WT_LSM_TREE owns the URI. */
cursor->uri = NULL;
if (clsm->lsm_tree != NULL)
__wt_lsm_tree_release(session, clsm->lsm_tree);
WT_TRET(__wt_cursor_close(cursor));
@@ -1744,7 +1742,7 @@ __wt_clsm_open(WT_SESSION_IMPL *session,
cursor = &clsm->iface;
*cursor = iface;
cursor->session = &session->iface;
cursor->uri = lsm_tree->name;
WT_ERR(__wt_strdup(session, lsm_tree->name, &cursor->uri));
cursor->key_format = lsm_tree->key_format;
cursor->value_format = lsm_tree->value_format;

View File

@@ -334,7 +334,7 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
__wt_spin_destroy(session, &manager->switch_lock);
__wt_spin_destroy(session, &manager->app_lock);
__wt_spin_destroy(session, &manager->manager_lock);
WT_TRET(__wt_cond_destroy(session, &manager->work_cond));
__wt_cond_destroy(session, &manager->work_cond);
return (ret);
}

View File

@@ -471,7 +471,7 @@ __lsm_tree_open(WT_SESSION_IMPL *session,
/* Try to open the tree. */
WT_RET(__wt_calloc_one(session, &lsm_tree));
__wt_rwlock_init(session, &lsm_tree->rwlock);
WT_ERR(__wt_rwlock_init(session, &lsm_tree->rwlock));
WT_ERR(__lsm_tree_set_name(session, lsm_tree, uri));

View File

@@ -328,8 +328,9 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
*/
saved_isolation = session->txn.isolation;
session->txn.isolation = WT_ISO_READ_UNCOMMITTED;
WT_ERR(__wt_cache_op(session, WT_SYNC_WRITE_LEAVES));
ret = __wt_cache_op(session, WT_SYNC_WRITE_LEAVES);
session->txn.isolation = saved_isolation;
WT_ERR(ret);
__wt_verbose(session, WT_VERB_LSM, "LSM worker checkpointing %s",
chunk->uri);

View File

@@ -266,6 +266,8 @@ __wt_strndup(WT_SESSION_IMPL *session, const void *str, size_t len, void *retp)
WT_RET(__wt_malloc(session, len + 1, &p));
WT_ASSERT(session, p != NULL); /* quiet clang scan-build */
/*
* Don't change this to strncpy, we rely on this function to duplicate
* "strings" that contain nul bytes.

View File

@@ -59,13 +59,17 @@
#include "wt_internal.h"
extern int __wt_opterr, __wt_optind, __wt_optopt, __wt_optreset;
extern int __wt_opterr WT_ATTRIBUTE_LIBRARY_VISIBLE;
extern int __wt_optind WT_ATTRIBUTE_LIBRARY_VISIBLE;
extern int __wt_optopt WT_ATTRIBUTE_LIBRARY_VISIBLE;
extern int __wt_optreset WT_ATTRIBUTE_LIBRARY_VISIBLE;
int __wt_opterr = 1, /* if error message should be printed */
__wt_optind = 1, /* index into parent argv vector */
__wt_optopt, /* character checked for validity */
__wt_optreset; /* reset getopt */
extern char *__wt_optarg;
extern char *__wt_optarg WT_ATTRIBUTE_LIBRARY_VISIBLE;
char *__wt_optarg; /* argument associated with option */
#define BADCH (int)'?'

View File

@@ -37,7 +37,13 @@ __wt_posix_directory_list(WT_FILE_SYSTEM *file_system,
dirallocsz = 0;
entries = NULL;
/*
* If opendir fails, we should have a NULL pointer with an error value,
* but various static analysis programs remain unconvinced, check both.
*/
WT_SYSCALL_RETRY(((dirp = opendir(directory)) == NULL ? -1 : 0), ret);
if (dirp == NULL && ret == 0)
ret = EINVAL;
if (ret != 0)
WT_RET_MSG(session, ret,
"%s: directory-list: opendir", directory);

View File

@@ -153,7 +153,7 @@ err:
* __wt_cond_destroy --
* Destroy a condition variable.
*/
int
void
__wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp)
{
WT_CONDVAR *cond;
@@ -161,11 +161,15 @@ __wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp)
cond = *condp;
if (cond == NULL)
return (0);
return;
if ((ret = pthread_cond_destroy(&cond->cond)) != 0)
WT_PANIC_MSG(
session, ret, "pthread_cond_destroy: %s", cond->name);
if ((ret = pthread_mutex_destroy(&cond->mtx)) != 0)
WT_PANIC_MSG(
session, ret, "pthread_mutex_destroy: %s", cond->name);
ret = pthread_cond_destroy(&cond->cond);
WT_TRET(pthread_mutex_destroy(&cond->mtx));
__wt_free(session, *condp);
return (ret);
}

View File

@@ -16,6 +16,7 @@ void
__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
{
struct timespec tmp;
WT_DECL_RET;
/*
@@ -27,21 +28,34 @@ __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
/*
* Read into a local variable so that we're comparing the correct
* value when we check for monotonic increasing time. There are
* many places we read into an unlocked global variable.
*/
#if defined(HAVE_CLOCK_GETTIME)
WT_SYSCALL_RETRY(clock_gettime(CLOCK_REALTIME, tsp), ret);
if (ret == 0)
WT_SYSCALL_RETRY(clock_gettime(CLOCK_REALTIME, &tmp), ret);
if (ret == 0) {
__wt_time_check_monotonic(session, &tmp);
tsp->tv_sec = tmp.tv_sec;
tsp->tv_nsec = tmp.tv_nsec;
return;
}
WT_PANIC_MSG(session, ret, "clock_gettime");
#elif defined(HAVE_GETTIMEOFDAY)
{
struct timeval v;
WT_SYSCALL_RETRY(gettimeofday(&v, NULL), ret);
if (ret == 0) {
tsp->tv_sec = v.tv_sec;
tsp->tv_nsec = v.tv_usec * WT_THOUSAND;
tmp.tv_sec = v.tv_sec;
tmp.tv_nsec = v.tv_usec * WT_THOUSAND;
__wt_time_check_monotonic(session, &tmp);
*tsp = tmp;
return;
}
WT_PANIC_MSG(session, ret, "gettimeofday");
}
#else
NO TIME-OF-DAY IMPLEMENTATION: see src/os_posix/os_time.c
#endif

View File

@@ -163,18 +163,16 @@ __wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond)
* __wt_cond_destroy --
* Destroy a condition variable.
*/
int
void
__wt_cond_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp)
{
WT_CONDVAR *cond;
cond = *condp;
if (cond == NULL)
return (0);
return;
/* Do nothing to delete Condition Variable */
DeleteCriticalSection(&cond->mtx);
__wt_free(session, *condp);
return (0);
}

View File

@@ -15,17 +15,18 @@
void
__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
{
struct timespec tmp;
FILETIME time;
uint64_t ns100;
WT_UNUSED(session);
GetSystemTimeAsFileTime(&time);
ns100 = (((int64_t)time.dwHighDateTime << 32) + time.dwLowDateTime)
- 116444736000000000LL;
tsp->tv_sec = ns100 / 10000000;
tsp->tv_nsec = (long)((ns100 % 10000000) * 100);
tmp.tv_sec = ns100 / 10000000;
tmp.tv_nsec = (long)((ns100 % 10000000) * 100);
__wt_time_check_monotonic(session, &tmp);
*tsp = tmp;
}
/*

View File

@@ -386,7 +386,7 @@ __wt_reconcile(WT_SESSION_IMPL *session, WT_REF *ref,
* In-memory splits: reconciliation of an internal page cannot handle
* a child page splitting during the reconciliation.
*/
__wt_writelock(session, &page->page_lock);
WT_PAGE_LOCK(session, page);
oldest_id = __wt_txn_oldest_id(session);
if (LF_ISSET(WT_EVICTING))
@@ -405,7 +405,7 @@ __wt_reconcile(WT_SESSION_IMPL *session, WT_REF *ref,
/* Initialize the reconciliation structure for each new run. */
if ((ret = __rec_write_init(
session, ref, flags, salvage, &session->reconcile)) != 0) {
__wt_writeunlock(session, &page->page_lock);
WT_PAGE_UNLOCK(session, page);
return (ret);
}
r = session->reconcile;
@@ -446,7 +446,7 @@ __wt_reconcile(WT_SESSION_IMPL *session, WT_REF *ref,
WT_TRET(__rec_write_wrapup_err(session, r, page));
/* Release the reconciliation lock. */
__wt_writeunlock(session, &page->page_lock);
WT_PAGE_UNLOCK(session, page);
/*
* If our caller can configure lookaside table reconciliation, flag if

View File

@@ -1105,7 +1105,6 @@ int
__wt_session_range_truncate(WT_SESSION_IMPL *session,
const char *uri, WT_CURSOR *start, WT_CURSOR *stop)
{
WT_CURSOR *cursor;
WT_DECL_RET;
int cmp;
bool local_start;
@@ -1134,12 +1133,13 @@ __wt_session_range_truncate(WT_SESSION_IMPL *session,
}
/*
* Cursor truncate is only supported for some objects, check for the
* supporting methods we need, range_truncate and compare.
* Cursor truncate is only supported for some objects, check for a
* supporting compare method.
*/
cursor = start == NULL ? stop : start;
if (cursor->compare == NULL)
WT_ERR(__wt_bad_object_type(session, cursor->uri));
if (start != NULL && start->compare == NULL)
WT_ERR(__wt_bad_object_type(session, start->uri));
if (stop != NULL && stop->compare == NULL)
WT_ERR(__wt_bad_object_type(session, stop->uri));
/*
* If both cursors set, check they're correctly ordered with respect to
@@ -1150,6 +1150,9 @@ __wt_session_range_truncate(WT_SESSION_IMPL *session,
* reference the same object and the keys are set.
*/
if (start != NULL && stop != NULL) {
/* quiet clang scan-build */
WT_ASSERT(session, start->compare != NULL);
WT_ERR(start->compare(start, stop, &cmp));
if (cmp > 0)
WT_ERR_MSG(session, EINVAL,

View File

@@ -229,7 +229,8 @@ __wt_session_lock_dhandle(
WT_ASSERT(session, !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
}
if (ret != EBUSY || (is_open && want_exclusive))
if (ret != EBUSY || (is_open && want_exclusive) ||
LF_ISSET(WT_DHANDLE_LOCK_ONLY))
return (ret);
lock_busy = true;
@@ -261,8 +262,8 @@ __wt_session_release_btree(WT_SESSION_IMPL *session)
* can get a handle without special flags.
*/
if (F_ISSET(dhandle, WT_DHANDLE_DISCARD | WT_DHANDLE_DISCARD_FORCE)) {
__session_find_dhandle(session,
dhandle->name, dhandle->checkpoint, &dhandle_cache);
WT_SAVE_DHANDLE(session, __session_find_dhandle(session,
dhandle->name, dhandle->checkpoint, &dhandle_cache));
if (dhandle_cache != NULL)
__session_discard_dhandle(session, dhandle_cache);
}

View File

@@ -27,7 +27,7 @@
*/
/*
* Based on "Spinlocks and Read-Write Locks" by Dr. Steven Fuerst:
* Inspired by "Spinlocks and Read-Write Locks" by Dr. Steven Fuerst:
* http://locklessinc.com/articles/locks/
*
* Dr. Fuerst further credits:
@@ -39,77 +39,46 @@
* by John Mellor-Crummey and Michael Scott in their landmark paper "Scalable
* Reader-Writer Synchronization for Shared-Memory Multiprocessors".
*
* The following is an explanation of this code. First, the underlying lock
* structure.
* The following is an explanation of our interpretation and implementation.
* First, the underlying lock structure.
*
* volatile union {
* uint64_t v; // Full 64-bit value
* struct {
* uint16_t writers; Now serving for writers
* uint16_t readers; Now serving for readers
* uint16_t next; Next available ticket number
* uint16_t __notused; Padding
* }
* uint8_t current; // Current ticket
* uint8_t next; // Next available ticket
* uint8_t reader; // Read queue ticket
* uint8_t __notused; // Padding
* uint16_t readers_active; // Count of active readers
* uint16_t readers_queued; // Count of queued readers
* } s;
* } u;
*
* First, imagine a store's 'take a number' ticket algorithm. A customer takes
* a unique ticket number and customers are served in ticket order. In the data
* structure, 'writers' is the next writer to be served, 'readers' is the next
* reader to be served, and 'next' is the next available ticket number.
* structure, 'next' is the ticket that will be allocated next, and 'current'
* is the ticket being served.
*
* Next, consider exclusive (write) locks. The 'now serving' number for writers
* is 'writers'. To lock, 'take a number' and wait until that number is being
* served; more specifically, atomically copy and increment the current value of
* 'next', and then wait until 'writers' equals that copied number.
* Next, consider exclusive (write) locks. To lock, 'take a number' and wait
* until that number is being served; more specifically, atomically increment
* 'next', and then wait until 'current' equals that allocated ticket.
*
* Shared (read) locks are similar. Like writers, readers atomically get the
* next number available. However, instead of waiting for 'writers' to equal
* their number, they wait for 'readers' to equal their number.
* Shared (read) locks are similar, except that readers can share a ticket
* (both with each other and with a single writer). Readers with a given
* ticket execute before the writer with that ticket. In other words, writers
* wait for both their ticket to become current and for all readers to exit
* the lock.
*
* This has the effect of queuing lock requests in the order they arrive
* (incidentally avoiding starvation).
* If there are no active writers (indicated by 'current' == 'next'), readers
* can immediately enter the lock by atomically incrementing 'readers_active'.
* When there are writers active, readers form a new queue by first setting
* 'reader' to 'next' (i.e. readers are scheduled after any queued writers,
* avoiding starvation), then atomically incrementing 'readers_queued'.
*
* Each lock/unlock pair requires incrementing both 'readers' and 'writers'.
* In the case of a reader, the 'readers' increment happens when the reader
* acquires the lock (to allow read-lock sharing), and the 'writers' increment
* happens when the reader releases the lock. In the case of a writer, both
* 'readers' and 'writers' are incremented when the writer releases the lock.
*
* For example, consider the following read (R) and write (W) lock requests:
*
* writers readers next
* 0 0 0
* R: ticket 0, readers match OK 0 1 1
* R: ticket 1, readers match OK 0 2 2
* R: ticket 2, readers match OK 0 3 3
* W: ticket 3, writers no match block 0 3 4
* R: ticket 2, unlock 1 3 4
* R: ticket 0, unlock 2 3 4
* R: ticket 1, unlock 3 3 4
* W: ticket 3, writers match OK 3 3 4
*
* Note the writer blocks until 'writers' equals its ticket number and it does
* not matter if readers unlock in order or not.
*
* Readers or writers entering the system after the write lock is queued block,
* and the next ticket holder (reader or writer) will unblock when the writer
* unlocks. An example, continuing from the last line of the above example:
*
* writers readers next
* W: ticket 3, writers match OK 3 3 4
* R: ticket 4, readers no match block 3 3 5
* R: ticket 5, readers no match block 3 3 6
* W: ticket 6, writers no match block 3 3 7
* W: ticket 3, unlock 4 4 7
* R: ticket 4, readers match OK 4 5 7
* R: ticket 5, readers match OK 4 6 7
*
* The 'next' field is a 2-byte value so the available ticket number wraps at
* 64K requests. If a thread's lock request is not granted until the 'next'
* field cycles and the same ticket is taken by another thread, we could grant
* a lock to two separate threads at the same time, and bad things happen: two
* writer threads or a reader thread and a writer thread would run in parallel,
* and lock waiters could be skipped if the unlocks race. This is unlikely, it
* only happens if a lock request is blocked by 64K other requests. The fix is
* to grow the lock structure fields, but the largest atomic instruction we have
* is 8 bytes, the structure has no room to grow.
* The 'next' field is a 1-byte value so the available ticket number wraps
* after 256 requests. If a thread's write lock request would cause the 'next'
* field to catch up with 'current', instead it waits to avoid the same ticket
* being allocated to multiple threads.
*/
#include "wt_internal.h"
@@ -118,12 +87,14 @@
* __wt_rwlock_init --
* Initialize a read/write lock.
*/
void
int
__wt_rwlock_init(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
WT_UNUSED(session);
l->u.v = 0;
l->u = 0;
WT_RET(__wt_cond_alloc(session, "rwlock wait", &l->cond_readers));
WT_RET(__wt_cond_alloc(session, "rwlock wait", &l->cond_writers));
return (0);
}
/*
@@ -133,9 +104,10 @@ __wt_rwlock_init(WT_SESSION_IMPL *session, WT_RWLOCK *l)
void
__wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
WT_UNUSED(session);
l->u.v = 0;
l->u = 0;
__wt_cond_destroy(session, &l->cond_readers);
__wt_cond_destroy(session, &l->cond_writers);
}
/*
@@ -149,46 +121,34 @@ __wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
WT_STAT_CONN_INCR(session, rwlock_read);
new = old = *l;
old.u.v = l->u.v;
/*
* This read lock can only be granted if the lock was last granted to
* a reader and there are no readers or writers blocked on the lock,
* that is, if this thread's ticket would be the next ticket granted.
* Do the cheap test to see if this can possibly succeed (and confirm
* the lock is in the correct state to grant this read lock).
*/
if (old.s.readers != old.s.next)
/* This read lock can only be granted if there are no active writers. */
if (old.u.s.current != old.u.s.next)
return (EBUSY);
/*
* The replacement lock value is a result of allocating a new ticket and
* incrementing the reader value to match it.
* The replacement lock value is a result of adding an active reader.
* Check for overflow: if the maximum number of readers are already
* active, no new readers can enter the lock.
*/
new.s.readers = new.s.next = old.s.next + 1;
return (__wt_atomic_cas64(&l->u, old.u, new.u) ? 0 : EBUSY);
new.u.v = old.u.v;
if (++new.u.s.readers_active == 0)
return (EBUSY);
/* We rely on this atomic operation to provide a barrier. */
return (__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v) ? 0 : EBUSY);
}
/*
* __wt_readlock_spin --
* Spin to get a read lock: only yield the CPU if the lock is held
* exclusive.
* __read_blocked --
* Check whether the current read lock request should keep waiting.
*/
void
__wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *l)
static bool
__read_blocked(WT_SESSION_IMPL *session)
{
/*
* Try to get the lock in a single operation if it is available to
* readers. This avoids the situation where multiple readers arrive
* concurrently and have to line up in order to enter the lock. For
* read-heavy workloads it can make a significant difference.
*/
while (__wt_try_readlock(session, l) != 0) {
if (l->s.writers_active > 0)
__wt_yield();
else
WT_PAUSE();
}
return (session->current_rwticket !=
session->current_rwlock->u.s.current);
}
/*
@@ -198,43 +158,95 @@ __wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *l)
void
__wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
uint16_t ticket;
WT_RWLOCK new, old;
int pause_cnt;
int16_t writers_active;
uint8_t ticket;
WT_STAT_CONN_INCR(session, rwlock_read);
WT_DIAGNOSTIC_YIELD;
/*
* Possibly wrap: if we have more than 64K lockers waiting, the ticket
* value will wrap and two lockers will simultaneously be granted the
* lock.
*/
ticket = __wt_atomic_fetch_add16(&l->s.next, 1);
for (pause_cnt = 0; ticket != l->s.readers;) {
for (;;) {
/*
* We failed to get the lock; pause before retrying and if we've
* paused enough, yield so we don't burn CPU to no purpose. This
* situation happens if there are more threads than cores in the
* system and we're thrashing on shared resources.
* Fast path: if there is no active writer, join the current
* group.
*/
if (++pause_cnt < WT_THOUSAND)
for (old.u.v = l->u.v;
old.u.s.current == old.u.s.next;
old.u.v = l->u.v) {
new.u.v = old.u.v;
/*
* Check for overflow: if the maximum number of readers
* are already active, no new readers can enter the
* lock.
*/
if (++new.u.s.readers_active == 0)
goto stall;
if (__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v))
return;
WT_PAUSE();
else
}
/*
* There is an active writer: join the next group.
*
* Limit how many readers can queue: don't allow more readers
* to queue than there are active writers (calculated as
* `next - current`): otherwise, in write-heavy workloads,
* readers can keep queuing up in front of writers and
* throughput is unstable.
*
* If the maximum number of readers are already queued, wait
* until we can get a valid ticket.
*/
writers_active = old.u.s.next - old.u.s.current;
if (old.u.s.readers_queued > writers_active) {
stall: __wt_cond_wait(session,
l->cond_readers, 10 * WT_THOUSAND, NULL);
continue;
}
/*
* If we are the first reader to queue, set the next read
* group. Note: don't re-read from the lock or we could race
* with a writer unlocking.
*/
new.u.v = old.u.v;
if (new.u.s.readers_queued++ == 0)
new.u.s.reader = new.u.s.next;
ticket = new.u.s.reader;
if (__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v))
break;
}
/* Wait for our group to start. */
for (pause_cnt = 0; ticket != l->u.s.current; pause_cnt++) {
if (pause_cnt < 1000)
WT_PAUSE();
else if (pause_cnt < 1200)
__wt_yield();
else {
session->current_rwlock = l;
session->current_rwticket = ticket;
__wt_cond_wait(session,
l->cond_readers, 10 * WT_THOUSAND, __read_blocked);
}
}
/*
* We're the only writer of the readers field, so the update does not
* need to be atomic.
*/
++l->s.readers;
/*
* Applications depend on a barrier here so that operations holding the
* lock see consistent data.
* lock see consistent data. The atomic operation above isn't
* sufficient here because we don't own the lock until our ticket comes
* up and whatever data we are protecting may have changed in the
* meantime.
*/
WT_READ_BARRIER();
/* Sanity check that we (still) have the lock. */
WT_ASSERT(session,
ticket == l->u.s.current && l->u.s.readers_active > 0);
}
/*
@@ -244,13 +256,22 @@ __wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
void
__wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
WT_UNUSED(session);
WT_RWLOCK new, old;
/*
* Increment the writers value (other readers are doing the same, make
* sure we don't race).
*/
(void)__wt_atomic_add16(&l->s.writers, 1);
do {
old.u.v = l->u.v;
WT_ASSERT(session, old.u.s.readers_active > 0);
/*
* Decrement the active reader count (other readers are doing
* the same, make sure we don't race).
*/
new.u.v = old.u.v;
--new.u.s.readers_active;
} while (!__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v));
if (new.u.s.readers_active == 0 && new.u.s.current != new.u.s.next)
__wt_cond_signal(session, l->cond_writers);
}
/*
@@ -264,22 +285,44 @@ __wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
WT_STAT_CONN_INCR(session, rwlock_write);
old = new = *l;
/*
* This write lock can only be granted if the lock was last granted to
* a writer and there are no readers or writers blocked on the lock,
* that is, if this thread's ticket would be the next ticket granted.
* Do the cheap test to see if this can possibly succeed (and confirm
* the lock is in the correct state to grant this write lock).
* This write lock can only be granted if no readers or writers blocked
* on the lock, that is, if this thread's ticket would be the next
* ticket granted. Check if this can possibly succeed (and confirm the
* lock is in the correct state to grant this write lock).
*/
if (old.s.writers != old.s.next)
old.u.v = l->u.v;
if (old.u.s.current != old.u.s.next || old.u.s.readers_active != 0)
return (EBUSY);
/* The replacement lock value is a result of allocating a new ticket. */
++new.s.next;
++new.s.writers_active;
return (__wt_atomic_cas64(&l->u, old.u, new.u) ? 0 : EBUSY);
/*
* We've checked above that there is no writer active (since
* `current == next`), so there should be no readers queued.
*/
WT_ASSERT(session, old.u.s.readers_queued == 0);
/*
* The replacement lock value is a result of allocating a new ticket.
*
* We rely on this atomic operation to provide a barrier.
*/
new.u.v = old.u.v;
new.u.s.next++;
return (__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v) ? 0 : EBUSY);
}
/*
* __write_blocked --
* Check whether the current write lock request should keep waiting.
*/
static bool
__write_blocked(WT_SESSION_IMPL *session)
{
WT_RWLOCK *l;
l = session->current_rwlock;
return (session->current_rwticket != l->u.s.current ||
l->u.s.readers_active != 0);
}
/*
@@ -289,36 +332,68 @@ __wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
void
__wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
uint16_t ticket;
WT_RWLOCK new, old;
int pause_cnt;
uint8_t ticket;
WT_STAT_CONN_INCR(session, rwlock_write);
/*
* Possibly wrap: if we have more than 64K lockers waiting, the ticket
* value will wrap and two lockers will simultaneously be granted the
* lock.
*/
ticket = __wt_atomic_fetch_add16(&l->s.next, 1);
(void)__wt_atomic_add16(&l->s.writers_active, 1);
for (pause_cnt = 0; ticket != l->s.writers;) {
for (;;) {
old.u.v = l->u.v;
/* Allocate a ticket. */
new.u.v = old.u.v;
ticket = new.u.s.next++;
/*
* We failed to get the lock; pause before retrying and if we've
* paused enough, sleep so we don't burn CPU to no purpose. This
* situation happens if there are more threads than cores in the
* system and we're thrashing on shared resources.
* Check for overflow: if the next ticket is allowed to catch
* up with the current batch, two writers could be granted the
* lock simultaneously.
*/
if (++pause_cnt < WT_THOUSAND)
if (new.u.s.current == new.u.s.next) {
__wt_cond_wait(session,
l->cond_writers, 10 * WT_THOUSAND, NULL);
continue;
}
if (__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v))
break;
}
/*
* Wait for our group to start and any readers to drain.
*
* We take care here to do an atomic read of the full 64-bit lock
* value. Otherwise, reads are not guaranteed to be ordered and we
* could see no readers active from a different batch and decide that
* we have the lock.
*/
for (pause_cnt = 0, old.u.v = l->u.v;
ticket != old.u.s.current || old.u.s.readers_active != 0;
pause_cnt++, old.u.v = l->u.v) {
if (pause_cnt < 1000)
WT_PAUSE();
else
__wt_sleep(0, 10);
else if (pause_cnt < 1200)
__wt_yield();
else {
session->current_rwlock = l;
session->current_rwticket = ticket;
__wt_cond_wait(session,
l->cond_writers, 10 * WT_THOUSAND, __write_blocked);
}
}
/*
* Applications depend on a barrier here so that operations holding the
* lock see consistent data.
* lock see consistent data. The atomic operation above isn't
* sufficient here because we don't own the lock until our ticket comes
* up and whatever data we are protecting may have changed in the
* meantime.
*/
WT_READ_BARRIER();
/* Sanity check that we (still) have the lock. */
WT_ASSERT(session,
ticket == l->u.s.current && l->u.s.readers_active == 0);
}
/*
@@ -328,29 +403,35 @@ __wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
void
__wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
WT_RWLOCK new;
WT_RWLOCK new, old;
WT_UNUSED(session);
do {
old.u.v = l->u.v;
(void)__wt_atomic_sub16(&l->s.writers_active, 1);
/*
* We're holding the lock exclusive, there shouldn't be any
* active readers.
*/
WT_ASSERT(session, old.u.s.readers_active == 0);
/*
* Ensure that all updates made while the lock was held are visible to
* the next thread to acquire the lock.
*/
WT_WRITE_BARRIER();
/*
* Allow the next batch to start.
*
* If there are readers in the next group, swap queued readers
* to active: this could race with new readlock requests, so we
* have to spin.
*/
new.u.v = old.u.v;
if (++new.u.s.current == new.u.s.reader) {
new.u.s.readers_active = new.u.s.readers_queued;
new.u.s.readers_queued = 0;
}
} while (!__wt_atomic_casv64(&l->u.v, old.u.v, new.u.v));
new = *l;
/*
* We're the only writer of the writers/readers fields, so the update
* does not need to be atomic; we have to update both values at the
* same time though, otherwise we'd potentially race with the thread
* next granted the lock.
*/
++new.s.writers;
++new.s.readers;
l->i.wr = new.i.wr;
if (new.u.s.readers_active != 0)
__wt_cond_signal(session, l->cond_readers);
else if (new.u.s.current != new.u.s.next)
__wt_cond_signal(session, l->cond_writers);
WT_DIAGNOSTIC_YIELD;
}
@@ -363,8 +444,11 @@ __wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
bool
__wt_rwlock_islocked(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
WT_RWLOCK old;
WT_UNUSED(session);
return (l->s.writers != l->s.next || l->s.readers != l->s.next);
old.u.v = l->u.v;
return (old.u.s.current != old.u.s.next || old.u.s.readers_active != 0);
}
#endif

View File

@@ -728,6 +728,7 @@ static const char * const __stats_connection_desc[] = {
"cache: unmodified pages evicted",
"connection: auto adjusting condition resets",
"connection: auto adjusting condition wait calls",
"connection: detected system time went backwards",
"connection: files currently open",
"connection: memory allocations",
"connection: memory frees",
@@ -1014,6 +1015,7 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
stats->cache_eviction_clean = 0;
stats->cond_auto_wait_reset = 0;
stats->cond_auto_wait = 0;
stats->time_travel = 0;
/* not clearing file_open */
stats->memory_allocation = 0;
stats->memory_free = 0;
@@ -1320,6 +1322,7 @@ __wt_stat_connection_aggregate(
to->cache_eviction_clean += WT_STAT_READ(from, cache_eviction_clean);
to->cond_auto_wait_reset += WT_STAT_READ(from, cond_auto_wait_reset);
to->cond_auto_wait += WT_STAT_READ(from, cond_auto_wait);
to->time_travel += WT_STAT_READ(from, time_travel);
to->file_open += WT_STAT_READ(from, file_open);
to->memory_allocation += WT_STAT_READ(from, memory_allocation);
to->memory_free += WT_STAT_READ(from, memory_free);

View File

@@ -257,7 +257,7 @@ __wt_thread_group_create(
__wt_verbose(session, WT_VERB_THREAD_GROUP,
"Creating thread group: %p", (void *)group);
__wt_rwlock_init(session, &group->lock);
WT_RET(__wt_rwlock_init(session, &group->lock));
WT_ERR(__wt_cond_alloc(
session, "thread group cond", &group->wait_cond));
cond_alloced = true;
@@ -272,7 +272,7 @@ __wt_thread_group_create(
/* Cleanup on error to avoid leaking resources */
err: if (ret != 0) {
if (cond_alloced)
WT_TRET(__wt_cond_destroy(session, &group->wait_cond));
__wt_cond_destroy(session, &group->wait_cond);
__wt_rwlock_destroy(session, &group->lock);
}
return (ret);
@@ -297,7 +297,7 @@ __wt_thread_group_destroy(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group)
__wt_free(session, group->threads);
WT_TRET(__wt_cond_destroy(session, &group->wait_cond));
__wt_cond_destroy(session, &group->wait_cond);
__wt_rwlock_destroy(session, &group->lock);
/*

View File

@@ -126,7 +126,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
n = 0;
/* We're going to scan the table: wait for the lock. */
__wt_readlock_spin(session, &txn_global->scan_rwlock);
__wt_readlock(session, &txn_global->scan_rwlock);
current_id = pinned_id = txn_global->current;
prev_oldest_id = txn_global->oldest_id;
@@ -293,7 +293,7 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
/* First do a read-only scan. */
if (wait)
__wt_readlock_spin(session, &txn_global->scan_rwlock);
__wt_readlock(session, &txn_global->scan_rwlock);
else if ((ret =
__wt_try_readlock(session, &txn_global->scan_rwlock)) != 0)
return (ret == EBUSY ? 0 : ret);
@@ -768,8 +768,8 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_spin_init(session,
&txn_global->id_lock, "transaction id lock"));
__wt_rwlock_init(session, &txn_global->scan_rwlock);
__wt_rwlock_init(session, &txn_global->nsnap_rwlock);
WT_RET(__wt_rwlock_init(session, &txn_global->scan_rwlock));
WT_RET(__wt_rwlock_init(session, &txn_global->nsnap_rwlock));
txn_global->nsnap_oldest_id = WT_TXN_NONE;
TAILQ_INIT(&txn_global->nsnaph);

View File

@@ -57,6 +57,9 @@ noinst_PROGRAMS += test_wt3135_search_near_collator
test_wt3184_dup_index_collator_SOURCES = wt3184_dup_index_collator/main.c
noinst_PROGRAMS += test_wt3184_dup_index_collator
test_rwlock_SOURCES = rwlock/main.c
noinst_PROGRAMS += test_rwlock
# Run this during a "make check" smoke test.
TESTS = $(noinst_PROGRAMS)
LOG_COMPILER = $(TEST_WRAPPER)

184
test/csuite/rwlock/main.c Normal file
View File

@@ -0,0 +1,184 @@
/*-
* Public Domain 2014-2017 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.
*/
#include "test_util.h"
/*
* JIRA ticket reference: HELP-4355
* Test rwlock collapse under load.
*/
#define MAX_THREADS 1000
#define READS_PER_WRITE 10000
//#define READS_PER_WRITE 1000000
//#define READS_PER_WRITE 100
#define CHECK_CORRECTNESS 1
//#define USE_POSIX 1
static WT_RWLOCK rwlock;
static pthread_rwlock_t p_rwlock;
static bool running;
static uint64_t shared_counter;
void *thread_rwlock(void *);
void *thread_dump(void *);
int
main(int argc, char *argv[])
{
TEST_OPTS *opts, _opts;
struct timespec te, ts;
pthread_t dump_id, id[MAX_THREADS];
int i;
if (!testutil_enable_long_tests()) /* Ignore unless requested */
return (EXIT_SUCCESS);
opts = &_opts;
memset(opts, 0, sizeof(*opts));
opts->nthreads = 100;
opts->nops = 1000000; /* per thread */
testutil_check(testutil_parse_opts(argc, argv, opts));
running = true;
testutil_make_work_dir(opts->home);
testutil_check(wiredtiger_open(opts->home, NULL,
"create,session_max=1000,statistics=(fast)", &opts->conn));
testutil_check(__wt_rwlock_init(NULL, &rwlock));
testutil_check(pthread_rwlock_init(&p_rwlock, NULL));
testutil_check(pthread_create(
&dump_id, NULL, thread_dump, (void *)opts));
__wt_epoch(NULL, &ts);
for (i = 0; i < (int)opts->nthreads; ++i)
testutil_check(pthread_create(
&id[i], NULL, thread_rwlock, (void *)opts));
while (--i >= 0)
testutil_check(pthread_join(id[i], NULL));
__wt_epoch(NULL, &te);
printf("%.2lf\n", WT_TIMEDIFF_MS(te, ts) / 1000.0);
running = false;
testutil_check(pthread_join(dump_id, NULL));
testutil_check(pthread_rwlock_destroy(&p_rwlock));
testutil_cleanup(opts);
return (EXIT_SUCCESS);
}
/*
* Acquire a rwlock, every Nth operation, acquire exclusive.
*/
void *
thread_rwlock(void *arg)
{
TEST_OPTS *opts;
WT_SESSION *wt_session;
WT_SESSION_IMPL *session;
uint64_t i, counter;
bool writelock;
opts = (TEST_OPTS *)arg;
testutil_check(
opts->conn->open_session(opts->conn, NULL, NULL, &wt_session));
session = (WT_SESSION_IMPL *)wt_session;
printf("Running rwlock thread\n");
for (i = 1; i <= opts->nops; ++i) {
writelock = (i % READS_PER_WRITE == 0);
#ifdef USE_POSIX
if (writelock)
testutil_check(pthread_rwlock_wrlock(&p_rwlock));
else
testutil_check(pthread_rwlock_rdlock(&p_rwlock));
#else
if (writelock)
__wt_writelock(session, &rwlock);
else
__wt_readlock(session, &rwlock);
#endif
/*
* Do a tiny amount of work inside the lock so the compiler
* can't optimize everything away.
*/
(void)__wt_atomic_add64(&counter, 1);
#ifdef CHECK_CORRECTNESS
if (writelock)
counter = ++shared_counter;
else
counter = shared_counter;
__wt_yield();
testutil_assert(counter == shared_counter);
#endif
#ifdef USE_POSIX
testutil_check(pthread_rwlock_unlock(&p_rwlock));
#else
if (writelock)
__wt_writeunlock(session, &rwlock);
else
__wt_readunlock(session, &rwlock);
#endif
if (i % 10000 == 0) {
printf("%s", session->id == 20 ? ".\n" : ".");
fflush(stdout);
}
}
opts->running = false;
return (NULL);
}
void *
thread_dump(void *arg) {
WT_UNUSED(arg);
while (running) {
sleep(1);
printf("\n"
"rwlock { current %" PRIu8 ", next %" PRIu8
", reader %" PRIu8 ", readers_active %" PRIu16
", readers_queued %" PRIu16 " }\n",
rwlock.u.s.current,
rwlock.u.s.next,
rwlock.u.s.reader,
rwlock.u.s.readers_active,
rwlock.u.s.readers_queued);
}
return (NULL);
}

View File

@@ -99,6 +99,7 @@ class test_cursor01(wttest.WiredTigerTestCase):
self.pr('creating cursor')
cursor = self.session.open_cursor(tablearg, None, None)
self.assertCursorHasNoKeyValue(cursor)
self.assertEqual(cursor.uri, tablearg)
for i in range(0, self.nentries):
cursor[self.genkey(i)] = self.genvalue(i)