/*- * Copyright (c) 2014-2020 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 *func; /* Function/line 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)) typedef TAILQ_HEAD(__wt_cursor_list, __wt_cursor) WT_CURSOR_LIST; /* Number of cursors cached to trigger cursor sweep. */ #define WT_SESSION_CURSOR_SWEEP_COUNTDOWN 40 /* Minimum number of buckets to visit during cursor sweep. */ #define WT_SESSION_CURSOR_SWEEP_MIN 5 /* Maximum number of buckets to visit during cursor sweep. */ #define WT_SESSION_CURSOR_SWEEP_MAX 32 /* * 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 */ uint64_t operation_start_us; /* Operation start */ uint64_t operation_timeout_us; /* Maximum operation period before rollback */ #ifdef HAVE_DIAGNOSTIC uint32_t op_5043_seconds; /* Temporary debugging to catch WT-5043, discard after 01/2020. */ #endif 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 data handle's 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; uint64_t last_sweep; /* Last sweep for dead handles */ struct timespec last_epoch; /* Last epoch time returned */ WT_CURSOR_LIST cursors; /* Cursors closed with the session */ uint32_t cursor_sweep_position; /* Position in cursor_cache for sweep */ uint32_t cursor_sweep_countdown; /* Countdown to cursor sweep */ uint64_t last_cursor_sweep; /* Last sweep for dead 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; 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) /* 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 /* * Variables used to look for violations of the contract that a session is only used by a single * session at once. */ volatile uintmax_t api_tid; volatile uint32_t api_enter_refcnt; /* * 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 *func; /* Allocating function, line */ int line; } * scratch_track; #endif WT_ITEM err; /* Error buffer */ WT_TXN_ISOLATION isolation; WT_TXN txn; /* Transaction state */ #define WT_SESSION_BG_SYNC_MSEC 1200000 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 */ uint64_t cache_wait_us; /* Wait time for cache for current operation */ /* * 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 */ /* AUTOMATIC FLAG VALUE GENERATION START */ #define WT_SESSION_BACKUP_CURSOR 0x00000001u #define WT_SESSION_BACKUP_DUP 0x00000002u #define WT_SESSION_CACHE_CURSORS 0x00000004u #define WT_SESSION_CAN_WAIT 0x00000008u #define WT_SESSION_IGNORE_CACHE_SIZE 0x00000010u #define WT_SESSION_INTERNAL 0x00000020u #define WT_SESSION_LOCKED_CHECKPOINT 0x00000040u #define WT_SESSION_LOCKED_HANDLE_LIST_READ 0x00000080u #define WT_SESSION_LOCKED_HANDLE_LIST_WRITE 0x00000100u #define WT_SESSION_LOCKED_HOTBACKUP_READ 0x00000200u #define WT_SESSION_LOCKED_HOTBACKUP_WRITE 0x00000400u #define WT_SESSION_LOCKED_METADATA 0x00000800u #define WT_SESSION_LOCKED_PASS 0x00001000u #define WT_SESSION_LOCKED_SCHEMA 0x00002000u #define WT_SESSION_LOCKED_SLOT 0x00004000u #define WT_SESSION_LOCKED_TABLE_READ 0x00008000u #define WT_SESSION_LOCKED_TABLE_WRITE 0x00010000u #define WT_SESSION_LOCKED_TURTLE 0x00020000u #define WT_SESSION_LOGGING_INMEM 0x00040000u #define WT_SESSION_LOOKASIDE_CURSOR 0x00080000u #define WT_SESSION_NO_DATA_HANDLES 0x00100000u #define WT_SESSION_NO_LOGGING 0x00200000u #define WT_SESSION_NO_RECONCILE 0x00400000u #define WT_SESSION_NO_SCHEMA_LOCK 0x00800000u #define WT_SESSION_QUIET_CORRUPT_FILE 0x01000000u #define WT_SESSION_READ_WONT_NEED 0x02000000u #define WT_SESSION_RESOLVING_TXN 0x04000000u #define WT_SESSION_SCHEMA_TXN 0x08000000u #define WT_SESSION_SERVER_ASYNC 0x10000000u /* AUTOMATIC FLAG VALUE GENERATION STOP */ 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 */ /* * Hash tables are allocated lazily as sessions are used to keep the size of this structure from * growing too large. */ WT_CURSOR_LIST *cursor_cache; /* Hash table of cached cursors */ /* Hashed handle reference list array */ TAILQ_HEAD(__dhandles_hash, __wt_data_handle_cache) * dhhash; /* Generations manager */ #define WT_GEN_CHECKPOINT 0 /* Checkpoint generation */ #define WT_GEN_COMMIT 1 /* Commit generation */ #define WT_GEN_EVICT 2 /* Eviction generation */ #define WT_GEN_HAZARD 3 /* Hazard pointer */ #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 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 */ /* * Operation tracking. */ WT_OPTRACK_RECORD *optrack_buf; u_int optrackbuf_ptr; uint64_t optrack_offset; WT_FH *optrack_fh; WT_SESSION_STATS stats; };