/*- * Copyright (c) 2014-2017 MongoDB, Inc. * Copyright (c) 2008-2014 WiredTiger, Inc. * All rights reserved. * * See the file LICENSE for redistribution information. */ /* * WT_DATA_HANDLE_CACHE -- * Per-session cache of handles to avoid synchronization when opening * cursors. */ struct __wt_data_handle_cache { WT_DATA_HANDLE *dhandle; TAILQ_ENTRY(__wt_data_handle_cache) q; TAILQ_ENTRY(__wt_data_handle_cache) hashq; }; /* * WT_HAZARD -- * A hazard pointer. */ struct __wt_hazard { WT_REF *ref; /* Page reference */ #ifdef HAVE_DIAGNOSTIC const char *file; /* File/line where hazard acquired */ int line; #endif }; /* Get the connection implementation for a session */ #define S2C(session) ((WT_CONNECTION_IMPL *)(session)->iface.connection) /* Get the btree for a session */ #define S2BT(session) ((WT_BTREE *)(session)->dhandle->handle) #define S2BT_SAFE(session) ((session)->dhandle == NULL ? NULL : S2BT(session)) /* * WT_SESSION_IMPL -- * Implementation of WT_SESSION. */ struct __wt_session_impl { WT_SESSION iface; void *lang_private; /* Language specific private storage */ u_int active; /* Non-zero if the session is in-use */ const char *name; /* Name */ const char *lastop; /* Last operation */ uint32_t id; /* UID, offset in session array */ WT_EVENT_HANDLER *event_handler;/* Application's event handlers */ WT_DATA_HANDLE *dhandle; /* Current data handle */ /* * Each session keeps a cache of data handles. The set of handles * can grow quite large so we maintain both a simple list and a hash * table of lists. The hash table key is based on a hash of the table * URI. The hash table list is kept in allocated memory that lives * across session close - so it is declared further down. */ /* 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; WT_CURSOR_BACKUP *bkp_cursor; /* Hot backup cursor */ WT_COMPACT_STATE *compact; /* Compaction information */ enum { WT_COMPACT_NONE=0, WT_COMPACT_RUNNING, WT_COMPACT_SUCCESS } compact_state; /* * Lookaside table cursor, sweep and eviction worker threads only. */ WT_CURSOR *las_cursor; /* Lookaside table cursor */ WT_CURSOR *meta_cursor; /* Metadata file */ void *meta_track; /* Metadata operation tracking */ void *meta_track_next; /* Current position */ void *meta_track_sub; /* Child transaction / save point */ size_t meta_track_alloc; /* Currently allocated */ int meta_track_nest; /* Nesting level of meta transaction */ #define WT_META_TRACKING(session) ((session)->meta_track_next != NULL) /* * Each session keeps a cache of table handles. The set of handles * can grow quite large so we maintain both a simple list and a hash * table of lists. The hash table list is kept in allocated memory * that lives across session close - so it is declared further down. */ 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 */ #ifdef HAVE_DIAGNOSTIC /* * It's hard to figure out from where a buffer was allocated after it's * leaked, so in diagnostic mode we track them; DIAGNOSTIC can't simply * add additional fields to WT_ITEM structures because they are visible * to applications, create a parallel structure instead. */ struct __wt_scratch_track { const char *file; /* Allocating file, line */ int line; } *scratch_track; #endif WT_ITEM err; /* Error buffer */ WT_TXN_ISOLATION isolation; WT_TXN txn; /* Transaction state */ WT_LSN bg_sync_lsn; /* Background sync operation LSN. */ u_int ncursors; /* Count of active file cursors. */ void *block_manager; /* Block-manager support */ int (*block_manager_cleanup)(WT_SESSION_IMPL *); /* Checkpoint handles */ WT_DATA_HANDLE **ckpt_handle; /* Handle list */ u_int ckpt_handle_next; /* Next empty slot */ size_t ckpt_handle_allocated; /* Bytes allocated */ /* * Operations acting on handles. * * The preferred pattern is to gather all of the required handles at * the beginning of an operation, then drop any other locks, perform * the operation, then release the handles. This cannot be easily * merged with the list of checkpoint handles because some operations * (such as compact) do checkpoints internally. */ WT_DATA_HANDLE **op_handle; /* Handle list */ u_int op_handle_next; /* Next empty slot */ size_t op_handle_allocated; /* Bytes allocated */ void *reconcile; /* Reconciliation support */ int (*reconcile_cleanup)(WT_SESSION_IMPL *); /* Sessions have an associated statistics bucket based on its ID. */ u_int stat_bucket; /* Statistics bucket offset */ uint32_t flags; /* * All of the following fields live at the end of the structure so it's * easier to clear everything but the fields that persist. */ #define WT_SESSION_CLEAR_SIZE (offsetof(WT_SESSION_IMPL, rnd)) /* * The random number state persists past session close because we don't * want to repeatedly use the same values for skiplist depth when the * application isn't caching sessions. */ WT_RAND_STATE rnd; /* Random number generation state */ /* Hashed handle reference list array */ TAILQ_HEAD(__dhandles_hash, __wt_data_handle_cache) *dhhash; /* Hashed table reference list array */ TAILQ_HEAD(__tables_hash, __wt_table) *tablehash; /* Generations manager */ #define WT_GEN_CHECKPOINT 0 /* Checkpoint generation */ #define WT_GEN_EVICT 1 /* Eviction generation */ #define WT_GEN_HAZARD 2 /* Hazard pointer */ #define WT_GEN_SCHEMA 3 /* Schema version */ #define WT_GEN_SPLIT 4 /* Page splits */ #define WT_GENERATIONS 5 /* Total generation manager entries */ volatile uint64_t generations[WT_GENERATIONS]; /* * Session memory persists past session close because it's accessed by * threads of control other than the thread owning the session. For * example, btree splits and hazard pointers can "free" memory that's * still in use. In order to eventually free it, it's stashed here with * with its generation number; when no thread is reading in generation, * the memory can be freed for real. */ struct __wt_session_stash { struct __wt_stash { void *p; /* Memory, length */ size_t len; uint64_t gen; /* Generation */ } *list; size_t cnt; /* Array entries */ size_t alloc; /* Allocated bytes */ } stash[WT_GENERATIONS]; /* * Hazard pointers. * * Hazard information persists past session close because it's accessed * by threads of control other than the thread owning the session. * * Use the non-NULL state of the hazard field to know if the session has * previously been initialized. */ #define WT_SESSION_FIRST_USE(s) \ ((s)->hazard == NULL) /* * The hazard pointer array grows as necessary, initialize with 250 * slots. */ #define WT_SESSION_INITIAL_HAZARD_SLOTS 250 uint32_t hazard_size; /* Hazard pointer array slots */ uint32_t hazard_inuse; /* Hazard pointer array slots in-use */ uint32_t nhazard; /* Count of active hazard pointers */ WT_HAZARD *hazard; /* Hazard pointer array */ };