1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
/*-
* Copyright (c) 2014-2015 MongoDB, Inc.
* Copyright (c) 2008-2014 WiredTiger, Inc.
* All rights reserved.
*
* See the file LICENSE for redistribution information.
*/
#include "wt_internal.h"
/*
* __wt_connection_open --
* Open a connection.
*/
int
__wt_connection_open(WT_CONNECTION_IMPL *conn, const char *cfg[])
{
WT_SESSION_IMPL *session;
/* Default session. */
session = conn->default_session;
WT_ASSERT(session, session->iface.connection == &conn->iface);
/*
* Tell internal server threads to run: this must be set before opening
* any sessions.
*/
F_SET(conn, WT_CONN_SERVER_RUN | WT_CONN_LOG_SERVER_RUN);
/* WT_SESSION_IMPL array. */
WT_RET(__wt_calloc(session,
conn->session_size, sizeof(WT_SESSION_IMPL), &conn->sessions));
/*
* Open the default session. We open this before starting service
* threads because those may allocate and use session resources that
* need to get cleaned up on close.
*/
WT_RET(__wt_open_internal_session(
conn, "connection", true, false, &session));
/*
* The connection's default session is originally a static structure,
* swap that out for a more fully-functional session. It's necessary
* to have this step: the session allocation code uses the connection's
* session, and if we pass a reference to the default session as the
* place to store the allocated session, things get confused and error
* handling can be corrupted. So, we allocate into a stack variable
* and then assign it on success.
*/
conn->default_session = session;
/*
* Publish: there must be a barrier to ensure the connection structure
* fields are set before other threads read from the pointer.
*/
WT_WRITE_BARRIER();
/* Create the cache. */
WT_RET(__wt_cache_create(session, cfg));
/* Initialize transaction support. */
WT_RET(__wt_txn_global_init(session, cfg));
return (0);
}
/*
* __wt_connection_close --
* Close a connection handle.
*/
int
__wt_connection_close(WT_CONNECTION_IMPL *conn)
{
WT_CONNECTION *wt_conn;
WT_DECL_RET;
WT_DLH *dlh;
WT_FH *fh;
WT_SESSION_IMPL *s, *session;
WT_TXN_GLOBAL *txn_global;
u_int i;
wt_conn = &conn->iface;
txn_global = &conn->txn_global;
session = conn->default_session;
/*
* We're shutting down. Make sure everything gets freed.
*
* It's possible that the eviction server is in the middle of a long
* operation, with a transaction ID pinned. In that case, we will loop
* here until the transaction ID is released, when the oldest
* transaction ID will catch up with the current ID.
*/
for (;;) {
__wt_txn_update_oldest(session, true);
if (txn_global->oldest_id == txn_global->current)
break;
__wt_yield();
}
/* Clear any pending async ops. */
WT_TRET(__wt_async_flush(session));
/*
* Shut down server threads other than the eviction server, which is
* needed later to close btree handles. Some of these threads access
* btree handles, so take care in ordering shutdown to make sure they
* exit before files are closed.
*/
F_CLR(conn, WT_CONN_SERVER_RUN);
WT_TRET(__wt_async_destroy(session));
WT_TRET(__wt_lsm_manager_destroy(session));
F_SET(conn, WT_CONN_CLOSING);
WT_TRET(__wt_checkpoint_server_destroy(session));
WT_TRET(__wt_statlog_destroy(session, true));
WT_TRET(__wt_sweep_destroy(session));
WT_TRET(__wt_evict_destroy(session));
/* Close open data handles. */
WT_TRET(__wt_conn_dhandle_discard(session));
/*
* Now that all data handles are closed, tell logging that a checkpoint
* has completed then shut down the log manager (only after closing
* data handles). The call to destroy the log manager is outside the
* conditional because we allocate the log path so that printlog can
* run without running logging or recovery.
*/
if (FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED))
WT_TRET(__wt_txn_checkpoint_log(
session, true, WT_TXN_LOG_CKPT_STOP, NULL));
F_CLR(conn, WT_CONN_LOG_SERVER_RUN);
WT_TRET(__wt_logmgr_destroy(session));
/* Free memory for collators, compressors, data sources. */
WT_TRET(__wt_conn_remove_collator(session));
WT_TRET(__wt_conn_remove_compressor(session));
WT_TRET(__wt_conn_remove_data_source(session));
WT_TRET(__wt_conn_remove_extractor(session));
/*
* Complain if files weren't closed, ignoring the lock file, we'll
* close it in a minute.
*/
TAILQ_FOREACH(fh, &conn->fhqh, q) {
if (fh == conn->lock_fh)
continue;
__wt_errx(session,
"Connection has open file handles: %s", fh->name);
WT_TRET(__wt_close(session, &fh));
fh = TAILQ_FIRST(&conn->fhqh);
}
/* Disconnect from shared cache - must be before cache destroy. */
WT_TRET(__wt_conn_cache_pool_destroy(session));
/* Discard the cache. */
WT_TRET(__wt_cache_destroy(session));
/* Discard transaction state. */
__wt_txn_global_destroy(session);
/* Close extensions, first calling any unload entry point. */
while ((dlh = TAILQ_FIRST(&conn->dlhqh)) != NULL) {
TAILQ_REMOVE(&conn->dlhqh, dlh, q);
if (dlh->terminate != NULL)
WT_TRET(dlh->terminate(wt_conn));
WT_TRET(__wt_dlclose(session, dlh));
}
/*
* Close the internal (default) session, and switch back to the dummy
* session in case of any error messages from the remaining operations
* while destroying the connection handle.
*/
if (session != &conn->dummy_session) {
WT_TRET(session->iface.close(&session->iface, NULL));
session = conn->default_session = &conn->dummy_session;
}
/*
* The session's split stash isn't discarded during normal session close
* because it may persist past the life of the session. Discard it now.
*/
if ((s = conn->sessions) != NULL)
for (i = 0; i < conn->session_size; ++s, ++i)
__wt_split_stash_discard_all(session, s);
/*
* The session's hazard pointer memory isn't discarded during normal
* session close because access to it isn't serialized. Discard it
* now.
*/
if ((s = conn->sessions) != NULL)
for (i = 0; i < conn->session_size; ++s, ++i)
if (s != session) {
/*
* If hash arrays were allocated,
* free them now.
*/
if (s->dhhash != NULL)
__wt_free(session, s->dhhash);
if (s->tablehash != NULL)
__wt_free(session, s->tablehash);
__wt_free(session, s->hazard);
}
/* Destroy the handle. */
WT_TRET(__wt_connection_destroy(conn));
return (ret);
}
/*
* __wt_connection_workers --
* Start the worker threads.
*/
int
__wt_connection_workers(WT_SESSION_IMPL *session, const char *cfg[])
{
/*
* Start the eviction thread.
*/
WT_RET(__wt_evict_create(session));
/*
* Start the handle sweep thread.
*/
WT_RET(__wt_sweep_create(session));
/*
* Start the optional statistics thread. Start statistics first so that
* other optional threads can know if statistics are enabled or not.
*/
WT_RET(__wt_statlog_create(session, cfg));
/* Start the optional async threads. */
WT_RET(__wt_async_create(session, cfg));
WT_RET(__wt_logmgr_create(session, cfg));
/* Run recovery. */
WT_RET(__wt_txn_recover(session));
/*
* Start the optional logging/archive thread.
* NOTE: The log manager must be started before checkpoints so that the
* checkpoint server knows if logging is enabled.
*/
WT_RET(__wt_logmgr_open(session));
/* Start the optional checkpoint thread. */
WT_RET(__wt_checkpoint_server_create(session, cfg));
return (0);
}
|