Skip to content

Commit

Permalink
Import wiredtiger-wiredtiger-2.4.0-428-gafcc82e.tar.gz from wiredtige…
Browse files Browse the repository at this point in the history
…r branch mongodb-2.8
  • Loading branch information
kangas committed Nov 24, 2014
1 parent 58e49b2 commit 792f66b
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 187 deletions.
105 changes: 80 additions & 25 deletions src/third_party/wiredtiger/src/btree/bt_evict.c
Expand Up @@ -13,7 +13,7 @@ static int __evict_lru_cmp(const void *, const void *);
static int __evict_lru_pages(WT_SESSION_IMPL *, int);
static int __evict_lru_walk(WT_SESSION_IMPL *, uint32_t);
static int __evict_pass(WT_SESSION_IMPL *);
static int __evict_walk(WT_SESSION_IMPL *, uint32_t *, uint32_t);
static int __evict_walk(WT_SESSION_IMPL *, uint32_t);
static int __evict_walk_file(WT_SESSION_IMPL *, u_int *, uint32_t);
static void *__evict_worker(void *);
static int __evict_server_work(WT_SESSION_IMPL *);
Expand Down Expand Up @@ -490,6 +490,13 @@ __evict_pass(WT_SESSION_IMPL *session)
* sleep, it's not something we can fix.
*/
if (F_ISSET(cache, WT_EVICT_NO_PROGRESS)) {
/*
* Back off if we aren't making progress: walks hold
* the handle list lock, which blocks other operations
* that can free space in cache, such as LSM discarding
* handles.
*/
__wt_sleep(0, 1000 * (long)loop);
if (F_ISSET(cache, WT_EVICT_STUCK))
break;
if (loop == 100) {
Expand Down Expand Up @@ -715,12 +722,13 @@ __evict_lru_walk(WT_SESSION_IMPL *session, uint32_t flags)
cache = S2C(session)->cache;

/* Get some more pages to consider for eviction. */
if ((ret = __evict_walk(session, &entries, flags)) != 0)
if ((ret = __evict_walk(session, flags)) != 0)
return (ret == EBUSY ? 0 : ret);

/* Sort the list into LRU order and restart. */
__wt_spin_lock(session, &cache->evict_lock);

entries = cache->evict_entries;
qsort(cache->evict,
entries, sizeof(WT_EVICT_ENTRY), __evict_lru_cmp);

Expand Down Expand Up @@ -815,18 +823,21 @@ __evict_server_work(WT_SESSION_IMPL *session)
* Fill in the array by walking the next set of pages.
*/
static int
__evict_walk(WT_SESSION_IMPL *session, u_int *entriesp, uint32_t flags)
__evict_walk(WT_SESSION_IMPL *session, uint32_t flags)
{
WT_BTREE *btree;
WT_CACHE *cache;
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
u_int max_entries, old_slot, retries, slot;
int incr, dhandle_locked;
WT_DECL_SPINLOCK_ID(id);

conn = S2C(session);
cache = S2C(session)->cache;
dhandle = NULL;
incr = dhandle_locked = 0;
retries = 0;

/* Increment the shared read generation. */
Expand All @@ -840,25 +851,52 @@ __evict_walk(WT_SESSION_IMPL *session, u_int *entriesp, uint32_t flags)
*/
__wt_txn_update_oldest(session);

/*
* Set the starting slot in the queue and the maximum pages added
* per walk.
*/
slot = cache->evict_entries;
max_entries = slot + WT_EVICT_WALK_INCR;
if (cache->evict_current == NULL)
WT_STAT_FAST_CONN_INCR(session, cache_eviction_queue_empty);
else
WT_STAT_FAST_CONN_INCR(session, cache_eviction_queue_not_empty);

/*
* Lock the dhandle list so sweeping cannot change the pointers out
* from under us. If the lock is not available, give up: there may be
* other work for us to do without a new walk.
* Set the starting slot in the queue and the maximum pages added
* per walk.
*/
WT_RET(__wt_spin_trylock(session, &conn->dhandle_lock, &id));
slot = cache->evict_entries;
max_entries = slot + WT_EVICT_WALK_INCR;

retry: while (slot < max_entries && ret == 0) {
/*
* If another thread is waiting on the eviction server to clear
* the walk point in a tree, give up.
*/
if (F_ISSET(cache, WT_EVICT_CLEAR_WALKS))
break;

/*
* Lock the dhandle list to find the next handle and bump its
* reference count to keep it alive while we sweep.
*/
if (!dhandle_locked) {
if ((ret = __wt_spin_trylock(
session, &conn->dhandle_lock, &id)) != 0)
break;
dhandle_locked = 1;
}

if (dhandle == NULL)
dhandle = SLIST_FIRST(&conn->dhlh);
else {
if (incr) {
WT_ASSERT(session, dhandle->session_ref > 0);
(void)WT_ATOMIC_SUB4(dhandle->session_ref, 1);
incr = 0;
}
dhandle = SLIST_NEXT(dhandle, l);
}

/* If we reach the end of the list, we're done. */
if (dhandle == NULL)
break;

retry: SLIST_FOREACH(dhandle, &conn->dhlh, l) {
/* Ignore non-file handles, or handles that aren't open. */
if (!WT_PREFIX_MATCH(dhandle->name, "file:") ||
!F_ISSET(dhandle, WT_DHANDLE_OPEN))
Expand Down Expand Up @@ -897,6 +935,11 @@ retry: SLIST_FOREACH(dhandle, &conn->dhlh, l) {
btree->evict_walk_skips = 0;
old_slot = slot;

(void)WT_ATOMIC_ADD4(dhandle->session_ref, 1);
incr = 1;
__wt_spin_unlock(session, &conn->dhandle_lock);
dhandle_locked = 0;

__wt_spin_lock(session, &cache->evict_walk_lock);

/*
Expand All @@ -919,23 +962,35 @@ retry: SLIST_FOREACH(dhandle, &conn->dhlh, l) {
else
btree->evict_walk_period = WT_MIN(
WT_MAX(1, 2 * btree->evict_walk_period), 1000);
}

if (ret != 0 || slot >= max_entries)
break;
if (incr) {
WT_ASSERT(session, dhandle->session_ref > 0);
(void)WT_ATOMIC_SUB4(dhandle->session_ref, 1);
incr = 0;
}

/* Walk the list of files a few times if we don't find enough pages. */
if (ret == 0 && slot < max_entries && ++retries < 10)
if (dhandle_locked) {
__wt_spin_unlock(session, &conn->dhandle_lock);
dhandle_locked = 0;
}

/*
* Walk the list of files a few times if we don't find enough pages.
* Try two passes through all the files, then only keep going if we
* are finding more candidates. Take care not to skip files on
* subsequent passes.
*/
if (!F_ISSET(cache, WT_EVICT_CLEAR_WALKS) && ret == 0 &&
slot < max_entries && (retries < 2 || (retries < 10 && slot > 0))) {
cache->evict_file_next = NULL;
++retries;
goto retry;
}

/* Remember the file we should visit first, next loop. */
if (dhandle != NULL)
dhandle = SLIST_NEXT(dhandle, l);
cache->evict_file_next = dhandle;

__wt_spin_unlock(session, &conn->dhandle_lock);

*entriesp = slot;
cache->evict_entries = slot;
return (ret);
}

Expand Down Expand Up @@ -1029,7 +1084,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, u_int *slotp, uint32_t flags)
page->type == WT_PAGE_ROW_INT) &&
++internal_pages > WT_EVICT_WALK_PER_FILE / 2 &&
!LF_ISSET(WT_EVICT_PASS_AGGRESSIVE))
break;
continue;

/*
* If this page has never been considered for eviction,
Expand Down
2 changes: 1 addition & 1 deletion src/third_party/wiredtiger/src/btree/bt_sync.c
Expand Up @@ -294,7 +294,7 @@ __evict_file(WT_SESSION_IMPL *session, int syncop)
page->modify != NULL &&
!__wt_txn_visible_all(session,
page->modify->rec_max_txn))
return (EBUSY);
WT_ERR(EBUSY);
if (syncop == WT_SYNC_DISCARD_FORCE)
F_SET(session, WT_SESSION_DISCARD_FORCE);
__wt_ref_out(session, ref);
Expand Down
31 changes: 11 additions & 20 deletions src/third_party/wiredtiger/src/conn/conn_dhandle.c
Expand Up @@ -80,7 +80,7 @@ __conn_dhandle_open_lock(
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
(!want_exclusive || lock_busy)) {
WT_RET(__wt_readlock(session, dhandle->rwlock));
is_open = F_ISSET(dhandle, WT_DHANDLE_OPEN);
is_open = F_ISSET(dhandle, WT_DHANDLE_OPEN) ? 1 : 0;
if (is_open && !want_exclusive)
return (0);
WT_RET(__wt_readunlock(session, dhandle->rwlock));
Expand Down Expand Up @@ -131,6 +131,7 @@ __wt_conn_dhandle_find(WT_SESSION_IMPL *session,
WT_DATA_HANDLE *dhandle;
uint64_t hash;

WT_UNUSED(flags); /* Only used in diagnostic builds */
conn = S2C(session);

/* We must be holding the handle list lock at a higher level. */
Expand Down Expand Up @@ -626,14 +627,9 @@ __conn_dhandle_remove(WT_SESSION_IMPL *session, int final)
conn = S2C(session);
dhandle = session->dhandle;

WT_ASSERT(session,
final || F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED));
WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED));

/*
* Check if the handle was reacquired by a session while we waited;
* this should only happen when called from the periodic sweep code, of
* course.
*/
/* Check if the handle was reacquired by a session while we waited. */
if (!final && dhandle->session_ref != 0)
return (EBUSY);

Expand All @@ -654,20 +650,16 @@ __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)

dhandle = session->dhandle;

/*
* We're called from the periodic sweep function and the final close;
* the former wants to continue if the handle is suddenly found to be
* busy, the latter wants to shut things down.
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
if (!final)
WT_ERR(EBUSY);
if (F_ISSET(dhandle, WT_DHANDLE_OPEN))
WT_ERR(__wt_conn_btree_sync_and_close(session, 0));
}

/*
* Try to remove the handle, protected by the data handle lock.
* Kludge: interrupt the eviction server in case it is holding the
* handle list lock.
*/
F_SET(S2C(session)->cache, WT_EVICT_CLEAR_WALKS);

/* Try to remove the handle, protected by the data handle lock. */
WT_WITH_DHANDLE_LOCK(session,
ret = __conn_dhandle_remove(session, final));

Expand All @@ -686,8 +678,7 @@ __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)
WT_CLEAR_BTREE_IN_SESSION(session);
}

err: WT_ASSERT(session, !final || ret == 0);
return (ret);
err: return (ret);
}

/*
Expand Down
46 changes: 19 additions & 27 deletions src/third_party/wiredtiger/src/conn/conn_sweep.c
Expand Up @@ -53,39 +53,31 @@ __sweep(WT_SESSION_IMPL *session)
if (dhandle->session_ref != 0 ||
now - dhandle->timeofdeath <= WT_DHANDLE_SWEEP_WAIT)
continue;

/*
* We don't set WT_DHANDLE_EXCLUSIVE deliberately, we
* want opens to block on us rather than returning an
* EBUSY error to the application.
*/
ret = __wt_try_writelock(session, dhandle->rwlock);
if (ret == EBUSY) {
ret = 0;
continue;
}
WT_RET(ret);

WT_WITH_DHANDLE(session, dhandle,
ret = __wt_conn_btree_sync_and_close(session, 0));
if (ret == EBUSY)
ret = 0;

WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
WT_RET(ret);
}

/*
* Attempt to discard the handle (the called function checks the
* handle-open flag after acquiring appropriate locks, which is
* why we don't do any special handling of EBUSY returns above,
* that path never cleared the handle-open flag.
* We don't set WT_DHANDLE_EXCLUSIVE deliberately, we want
* opens to block on us rather than returning an EBUSY error to
* the application.
*/
if ((ret =
__wt_try_writelock(session, dhandle->rwlock)) == EBUSY)
continue;
WT_RET(ret);

/*
* Attempt to discard the handle. The called function
* re-checks that the handle is not in use, which is why we
* don't do any special handling of EBUSY returns above.
*/
WT_WITH_DHANDLE(session, dhandle,
ret = __wt_conn_dhandle_discard_single(session, 0));
if (ret == EBUSY)
ret = 0;
WT_RET(ret);

/* If the handle wasn't discarded, drop our lock. */
if (ret != 0)
WT_TRET(__wt_writeunlock(session, dhandle->rwlock));

WT_RET_BUSY_OK(ret);
}
return (0);
}
Expand Down
3 changes: 1 addition & 2 deletions src/third_party/wiredtiger/src/cursor/cur_backup.c
Expand Up @@ -254,8 +254,7 @@ __backup_start(
WT_ERR(__backup_list_append(
session, cb, WT_INCREMENTAL_BACKUP));
} else {
WT_ERR(__backup_list_append(
session, cb, WT_METADATA_BACKUP));
WT_ERR(__backup_list_append(session, cb, WT_METADATA_BACKUP));
WT_ERR(__wt_exist(session, WT_BASECONFIG, &exist));
if (exist)
WT_ERR(__backup_list_append(
Expand Down
21 changes: 11 additions & 10 deletions src/third_party/wiredtiger/src/cursor/cur_file.c
Expand Up @@ -459,17 +459,18 @@ __wt_curfile_open(WT_SESSION_IMPL *session, const char *uri,
if (WT_PREFIX_MATCH(uri, "file:")) {
/*
* If we are opening a bulk cursor, get the handle while
* holding the schema lock. This prevents a bulk cursor open
* failing with EBUSY due to a database-wide checkpoint.
* holding the checkpoint lock. This prevents a bulk cursor
* open failing with EBUSY due to a database-wide checkpoint.
*/
if (bulk) {
WT_WITH_SCHEMA_LOCK(session,
ret = __wt_session_get_btree_ckpt(
session, uri, cfg, flags));
WT_RET(ret);
} else
WT_RET(__wt_session_get_btree_ckpt(
session, uri, cfg, flags));
if (bulk)
__wt_spin_lock(
session, &S2C(session)->checkpoint_lock);
ret = __wt_session_get_btree_ckpt(
session, uri, cfg, flags);
if (bulk)
__wt_spin_unlock(
session, &S2C(session)->checkpoint_lock);
WT_RET(ret);
} else
WT_RET(__wt_bad_object_type(session, uri));

Expand Down
10 changes: 5 additions & 5 deletions src/third_party/wiredtiger/src/include/cache.i
Expand Up @@ -82,12 +82,12 @@ __wt_cache_full_check(WT_SESSION_IMPL *session)
int busy, count, full;

/*
* LSM sets the no-cache-check flag when holding the LSM tree lock,
* in that case, or when holding the schema lock, we don't want to
* highjack the thread for eviction.
* LSM sets the no-cache-check flag when holding the LSM tree lock, in
* that case, or when holding the schema or handle list locks (which
* block eviction), we don't want to highjack the thread for eviction.
*/
if (F_ISSET(session,
WT_SESSION_NO_CACHE_CHECK | WT_SESSION_SCHEMA_LOCKED))
if (F_ISSET(session, WT_SESSION_NO_CACHE_CHECK |
WT_SESSION_SCHEMA_LOCKED | WT_SESSION_HANDLE_LIST_LOCKED))
return (0);

/*
Expand Down

0 comments on commit 792f66b

Please sign in to comment.