1 /*-
2  * Copyright (c) 2014-2018 MongoDB, Inc.
3  * Copyright (c) 2008-2014 WiredTiger, Inc.
4  *	All rights reserved.
5  *
6  * See the file LICENSE for redistribution information.
7  */
8 
9 #define	MAX_ASYNC_SLEEP_USECS	100000	/* Maximum sleep waiting for work */
10 #define	MAX_ASYNC_YIELD		200	/* Maximum number of yields for work */
11 
12 #define	O2C(op)	((WT_CONNECTION_IMPL *)(op)->iface.connection)
13 #define	O2S(op)								\
14     (((WT_CONNECTION_IMPL *)(op)->iface.connection)->default_session)
15 /*
16  * WT_ASYNC_FORMAT --
17  *	The URI/config/format cache.
18  */
19 struct __wt_async_format {
20 	TAILQ_ENTRY(__wt_async_format) q;
21 	const char	*config;
22 	uint64_t	cfg_hash;		/* Config hash */
23 	const char	*uri;
24 	uint64_t	uri_hash;		/* URI hash */
25 	const char	*key_format;
26 	const char	*value_format;
27 };
28 
29 /*
30  * WT_ASYNC_OP_IMPL --
31  *	Implementation of the WT_ASYNC_OP.
32  */
33 struct __wt_async_op_impl {
34 	WT_ASYNC_OP	iface;
35 
36 	WT_ASYNC_CALLBACK	*cb;
37 
38 	uint32_t	internal_id;	/* Array position id. */
39 	uint64_t	unique_id;	/* Unique identifier. */
40 
41 	WT_ASYNC_FORMAT *format;	/* Format structure */
42 
43 #define	WT_ASYNCOP_ENQUEUED	0	/* Placed on the work queue */
44 #define	WT_ASYNCOP_FREE		1	/* Able to be allocated to user */
45 #define	WT_ASYNCOP_READY	2	/* Allocated, ready for user to use */
46 #define	WT_ASYNCOP_WORKING	3	/* Operation in progress by worker */
47 	uint32_t	state;
48 
49 	WT_ASYNC_OPTYPE	optype;		/* Operation type */
50 };
51 
52 /*
53  * Definition of the async subsystem.
54  */
55 struct __wt_async {
56 	/*
57 	 * Ops array protected by the ops_lock.
58 	 */
59 	WT_SPINLOCK		 ops_lock;      /* Locked: ops array */
60 	WT_ASYNC_OP_IMPL	 *async_ops;	/* Async ops */
61 #define	OPS_INVALID_INDEX	0xffffffff
62 	uint32_t		 ops_index;	/* Active slot index */
63 	uint64_t		 op_id;		/* Unique ID counter */
64 	WT_ASYNC_OP_IMPL	 **async_queue;	/* Async ops work queue */
65 	uint32_t		 async_qsize;	/* Async work queue size */
66 	/*
67 	 * We need to have two head and tail values.  All but one is
68 	 * maintained as an ever increasing value to ease wrap around.
69 	 *
70 	 * alloc_head: the next one to allocate for producers.
71 	 * head: the current head visible to consumers.
72 	 * head is always <= alloc_head.
73 	 * alloc_tail: the next slot for consumers to dequeue.
74 	 * alloc_tail is always <= head.
75 	 * tail_slot: the last slot consumed.
76 	 * A producer may need wait for tail_slot to advance.
77 	 */
78 	uint64_t		 alloc_head;	/* Next slot to enqueue */
79 	uint64_t		 head;		/* Head visible to worker */
80 	uint64_t		 alloc_tail;	/* Next slot to dequeue */
81 	uint64_t		 tail_slot;	/* Worker slot consumed */
82 
83 	TAILQ_HEAD(__wt_async_format_qh, __wt_async_format) formatqh;
84 	uint32_t		 cur_queue;	/* Currently enqueued */
85 	uint32_t		 max_queue;	/* Maximum enqueued */
86 
87 #define	WT_ASYNC_FLUSH_NONE		0	/* No flush in progress */
88 #define	WT_ASYNC_FLUSH_COMPLETE		1	/* Notify flush caller done */
89 #define	WT_ASYNC_FLUSH_IN_PROGRESS	2	/* Prevent other callers */
90 #define	WT_ASYNC_FLUSHING		3	/* Notify workers */
91 	uint32_t	 	 flush_state;
92 
93 	/* Notify any waiting threads when flushing is done. */
94 	WT_CONDVAR		*flush_cond;
95 	WT_ASYNC_OP_IMPL	 flush_op;	/* Special flush op */
96 	uint32_t		 flush_count;	/* Worker count */
97 	uint64_t		 flush_gen;	/* Flush generation number */
98 
99 #define	WT_ASYNC_MAX_WORKERS	20
100 	WT_SESSION_IMPL		*worker_sessions[WT_ASYNC_MAX_WORKERS];
101 					/* Async worker threads */
102 	wt_thread_t		 worker_tids[WT_ASYNC_MAX_WORKERS];
103 
104 	uint32_t		 flags;	/* Currently unused. */
105 };
106 
107 /*
108  * WT_ASYNC_CURSOR --
109  *	Async container for a cursor.  Each async worker thread
110  *	has a cache of async cursors to reuse for operations.
111  */
112 struct __wt_async_cursor {
113 	TAILQ_ENTRY(__wt_async_cursor) q;	/* Worker cache */
114 	uint64_t	cfg_hash;		/* Config hash */
115 	uint64_t	uri_hash;		/* URI hash */
116 	WT_CURSOR	*c;			/* WT cursor */
117 };
118 
119 /*
120  * WT_ASYNC_WORKER_STATE --
121  *	State for an async worker thread.
122  */
123 struct __wt_async_worker_state {
124 	uint32_t	id;
125 	TAILQ_HEAD(__wt_cursor_qh, __wt_async_cursor)	cursorqh;
126 	uint32_t	num_cursors;
127 };
128