Files
mongo/src/include/cache.i
sueloverso 5fe33c475e WT-2660 Fill in pct_full before returning. (#2751)
* WT-2660 Fix eviction hang when closing.

* Real fix: return if we're closing the connection.

* Move check for connection close into wt_eviction_needed.

* Fill in pct_full before returning.

* Whitespace
2016-05-26 14:26:57 -04:00

271 lines
6.7 KiB
OpenEdge ABL

/*-
* Copyright (c) 2014-2016 MongoDB, Inc.
* Copyright (c) 2008-2014 WiredTiger, Inc.
* All rights reserved.
*
* See the file LICENSE for redistribution information.
*/
/*
* __wt_cache_read_gen --
* Get the current read generation number.
*/
static inline uint64_t
__wt_cache_read_gen(WT_SESSION_IMPL *session)
{
return (S2C(session)->cache->read_gen);
}
/*
* __wt_cache_read_gen_incr --
* Increment the current read generation number.
*/
static inline void
__wt_cache_read_gen_incr(WT_SESSION_IMPL *session)
{
++S2C(session)->cache->read_gen;
}
/*
* __wt_cache_read_gen_bump --
* Update the page's read generation.
*/
static inline void
__wt_cache_read_gen_bump(WT_SESSION_IMPL *session, WT_PAGE *page)
{
/* Ignore pages set for forcible eviction. */
if (page->read_gen == WT_READGEN_OLDEST)
return;
/* Ignore pages already in the future. */
if (page->read_gen > __wt_cache_read_gen(session))
return;
/*
* We set read-generations in the future (where "the future" is measured
* by increments of the global read generation). The reason is because
* when acquiring a new hazard pointer for a page, we can check its read
* generation, and if the read generation isn't less than the current
* global generation, we don't bother updating the page. In other
* words, the goal is to avoid some number of updates immediately after
* each update we have to make.
*/
page->read_gen = __wt_cache_read_gen(session) + WT_READGEN_STEP;
}
/*
* __wt_cache_read_gen_new --
* Get the read generation for a new page in memory.
*/
static inline void
__wt_cache_read_gen_new(WT_SESSION_IMPL *session, WT_PAGE *page)
{
WT_CACHE *cache;
cache = S2C(session)->cache;
page->read_gen =
(__wt_cache_read_gen(session) + cache->read_gen_oldest) / 2;
}
/*
* __wt_cache_pages_inuse --
* Return the number of pages in use.
*/
static inline uint64_t
__wt_cache_pages_inuse(WT_CACHE *cache)
{
return (cache->pages_inmem - cache->pages_evict);
}
/*
* __wt_cache_bytes_inuse --
* Return the number of bytes in use.
*/
static inline uint64_t
__wt_cache_bytes_inuse(WT_CACHE *cache)
{
uint64_t bytes_inuse;
/* Adjust the cache size to take allocation overhead into account. */
bytes_inuse = cache->bytes_inmem;
if (cache->overhead_pct != 0)
bytes_inuse +=
(bytes_inuse * (uint64_t)cache->overhead_pct) / 100;
return (bytes_inuse);
}
/*
* __wt_cache_dirty_inuse --
* Return the number of dirty bytes in use.
*/
static inline uint64_t
__wt_cache_dirty_inuse(WT_CACHE *cache)
{
uint64_t dirty_inuse;
dirty_inuse = cache->bytes_dirty;
if (cache->overhead_pct != 0)
dirty_inuse +=
(dirty_inuse * (uint64_t)cache->overhead_pct) / 100;
return (dirty_inuse);
}
/*
* __wt_session_can_wait --
* Return if a session available for a potentially slow operation.
*/
static inline int
__wt_session_can_wait(WT_SESSION_IMPL *session)
{
/*
* Return if a session available for a potentially slow operation;
* for example, used by the block manager in the case of flushing
* the system cache.
*/
if (!F_ISSET(session, WT_SESSION_CAN_WAIT))
return (0);
/*
* LSM sets the no-eviction 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.
*/
if (F_ISSET(session, WT_SESSION_NO_EVICTION | WT_SESSION_LOCKED_SCHEMA))
return (0);
return (1);
}
/*
* __wt_eviction_dirty_target --
* Return if the eviction server is running to reduce the number of dirty
* pages (versus running to discard pages from the cache).
*/
static inline bool
__wt_eviction_dirty_target(WT_SESSION_IMPL *session)
{
return (FLD_ISSET(S2C(session)->cache->state, WT_EVICT_PASS_DIRTY));
}
/*
* __wt_eviction_needed --
* Return if an application thread should do eviction, and the cache full
* percentage as a side-effect.
*/
static inline bool
__wt_eviction_needed(WT_SESSION_IMPL *session, u_int *pct_fullp)
{
WT_CONNECTION_IMPL *conn;
WT_CACHE *cache;
uint64_t bytes_inuse, bytes_max;
u_int pct_full;
conn = S2C(session);
cache = conn->cache;
/*
* If the connection is closing we do not need eviction from an
* application thread. The eviction subsystem is already closed.
*/
if (F_ISSET(conn, WT_CONN_CLOSING))
return (false);
/*
* Avoid division by zero if the cache size has not yet been set in a
* shared cache.
*/
bytes_inuse = __wt_cache_bytes_inuse(cache);
bytes_max = conn->cache_size + 1;
/*
* Calculate the cache full percentage; anything over the trigger means
* we involve the application thread.
*/
pct_full = (u_int)((100 * bytes_inuse) / bytes_max);
if (pct_fullp != NULL)
*pct_fullp = pct_full;
/*
* If the connection is closing we do not need eviction from an
* application thread. The eviction subsystem is already closed.
* We return here because some callers depend on the percent full
* having been filled in.
*/
if (F_ISSET(conn, WT_CONN_CLOSING))
return (false);
if (pct_full > cache->eviction_trigger)
return (true);
/* Return if there are too many dirty bytes in cache. */
if (__wt_cache_dirty_inuse(cache) >
(cache->eviction_dirty_trigger * bytes_max) / 100)
return (true);
return (false);
}
/*
* __wt_cache_full --
* Return if the cache is at (or over) capacity.
*/
static inline bool
__wt_cache_full(WT_SESSION_IMPL *session)
{
WT_CONNECTION_IMPL *conn;
WT_CACHE *cache;
conn = S2C(session);
cache = conn->cache;
return (__wt_cache_bytes_inuse(cache) >= conn->cache_size);
}
/*
* __wt_cache_eviction_check --
* Evict pages if the cache crosses its boundaries.
*/
static inline int
__wt_cache_eviction_check(WT_SESSION_IMPL *session, bool busy, bool *didworkp)
{
WT_BTREE *btree;
u_int pct_full;
if (didworkp != NULL)
*didworkp = false;
/*
* 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_EVICTION |
WT_SESSION_LOCKED_HANDLE_LIST | WT_SESSION_LOCKED_SCHEMA))
return (0);
/* In memory configurations don't block when the cache is full. */
if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY))
return (0);
/*
* Threads operating on cache-resident trees are ignored because they're
* not contributing to the problem.
*/
btree = S2BT_SAFE(session);
if (btree != NULL && F_ISSET(btree, WT_BTREE_IN_MEMORY))
return (0);
/* Check if eviction is needed. */
if (!__wt_eviction_needed(session, &pct_full))
return (0);
/*
* Some callers (those waiting for slow operations), will sleep if there
* was no cache work to do. After this point, let them skip the sleep.
*/
if (didworkp != NULL)
*didworkp = true;
return (__wt_cache_eviction_worker(session, busy, pct_full));
}