Change BSD-2.0 to BSD-3-Clause
[platform/upstream/db4.git] / txn / txn_region.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5  *
6  * $Id$
7  */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12 #include "dbinc/log.h"
13 #include "dbinc/txn.h"
14
15 static int __txn_init __P((ENV *, DB_TXNMGR *));
16 static size_t __txn_region_size __P((ENV *));
17
18 /*
19  * __txn_open --
20  *      Open a transaction region.
21  *
22  * PUBLIC: int __txn_open __P((ENV *, int));
23  */
24 int
25 __txn_open(env, create_ok)
26         ENV *env;
27         int create_ok;
28 {
29         DB_TXNMGR *mgr;
30         int ret;
31
32         /* Create/initialize the transaction manager structure. */
33         if ((ret = __os_calloc(env, 1, sizeof(DB_TXNMGR), &mgr)) != 0)
34                 return (ret);
35         TAILQ_INIT(&mgr->txn_chain);
36         mgr->env = env;
37
38         /* Join/create the txn region. */
39         mgr->reginfo.env = env;
40         mgr->reginfo.type = REGION_TYPE_TXN;
41         mgr->reginfo.id = INVALID_REGION_ID;
42         mgr->reginfo.flags = REGION_JOIN_OK;
43         if (create_ok)
44                 F_SET(&mgr->reginfo, REGION_CREATE_OK);
45         if ((ret = __env_region_attach(env,
46             &mgr->reginfo, __txn_region_size(env))) != 0)
47                 goto err;
48
49         /* If we created the region, initialize it. */
50         if (F_ISSET(&mgr->reginfo, REGION_CREATE))
51                 if ((ret = __txn_init(env, mgr)) != 0)
52                         goto err;
53
54         /* Set the local addresses. */
55         mgr->reginfo.primary =
56             R_ADDR(&mgr->reginfo, mgr->reginfo.rp->primary);
57
58         /* If threaded, acquire a mutex to protect the active TXN list. */
59         if ((ret = __mutex_alloc(
60             env, MTX_TXN_ACTIVE, DB_MUTEX_PROCESS_ONLY, &mgr->mutex)) != 0)
61                 goto err;
62
63         env->tx_handle = mgr;
64         return (0);
65
66 err:    env->tx_handle = NULL;
67         if (mgr->reginfo.addr != NULL)
68                 (void)__env_region_detach(env, &mgr->reginfo, 0);
69
70         (void)__mutex_free(env, &mgr->mutex);
71         __os_free(env, mgr);
72         return (ret);
73 }
74
75 /*
76  * __txn_init --
77  *      Initialize a transaction region in shared memory.
78  */
79 static int
80 __txn_init(env, mgr)
81         ENV *env;
82         DB_TXNMGR *mgr;
83 {
84         DB_ENV *dbenv;
85         DB_LSN last_ckp;
86         DB_TXNREGION *region;
87         int ret;
88
89         dbenv = env->dbenv;
90
91         /*
92          * Find the last checkpoint in the log.
93          */
94         ZERO_LSN(last_ckp);
95         if (LOGGING_ON(env)) {
96                 /*
97                  * The log system has already walked through the last
98                  * file.  Get the LSN of a checkpoint it may have found.
99                  */
100                 if ((ret = __log_get_cached_ckp_lsn(env, &last_ckp)) != 0)
101                         return (ret);
102
103                 /*
104                  * If that didn't work, look backwards from the beginning of
105                  * the last log file until we find the last checkpoint.
106                  */
107                 if (IS_ZERO_LSN(last_ckp) &&
108                     (ret = __txn_findlastckp(env, &last_ckp, NULL)) != 0)
109                         return (ret);
110         }
111
112         if ((ret = __env_alloc(&mgr->reginfo,
113             sizeof(DB_TXNREGION), &mgr->reginfo.primary)) != 0) {
114                 __db_errx(env,
115                     "Unable to allocate memory for the transaction region");
116                 return (ret);
117         }
118         mgr->reginfo.rp->primary =
119             R_OFFSET(&mgr->reginfo, mgr->reginfo.primary);
120         region = mgr->reginfo.primary;
121         memset(region, 0, sizeof(*region));
122
123         if ((ret = __mutex_alloc(
124             env, MTX_TXN_REGION, 0, &region->mtx_region)) != 0)
125                 return (ret);
126         mgr->reginfo.mtx_alloc = region->mtx_region;
127
128         region->maxtxns = dbenv->tx_max;
129         region->last_txnid = TXN_MINIMUM;
130         region->cur_maxid = TXN_MAXIMUM;
131
132         if ((ret = __mutex_alloc(
133             env, MTX_TXN_CHKPT, 0, &region->mtx_ckp)) != 0)
134                 return (ret);
135         region->last_ckp = last_ckp;
136         region->time_ckp = time(NULL);
137
138         memset(&region->stat, 0, sizeof(region->stat));
139 #ifdef HAVE_STATISTICS
140         region->stat.st_maxtxns = region->maxtxns;
141 #endif
142
143         SH_TAILQ_INIT(&region->active_txn);
144         SH_TAILQ_INIT(&region->mvcc_txn);
145         return (ret);
146 }
147
148 /*
149  * __txn_findlastckp --
150  *      Find the last checkpoint in the log, walking backwards from the
151  *      max_lsn given or the beginning of the last log file.  (The
152  *      log system looked through the last log file when it started up.)
153  *
154  * PUBLIC: int __txn_findlastckp __P((ENV *, DB_LSN *, DB_LSN *));
155  */
156 int
157 __txn_findlastckp(env, lsnp, max_lsn)
158         ENV *env;
159         DB_LSN *lsnp;
160         DB_LSN *max_lsn;
161 {
162         DBT dbt;
163         DB_LOGC *logc;
164         DB_LSN lsn;
165         int ret, t_ret;
166         u_int32_t rectype;
167
168         ZERO_LSN(*lsnp);
169
170         if ((ret = __log_cursor(env, &logc)) != 0)
171                 return (ret);
172
173         /* Get the last LSN. */
174         memset(&dbt, 0, sizeof(dbt));
175         if (max_lsn != NULL) {
176                 lsn = *max_lsn;
177                 if ((ret = __logc_get(logc, &lsn, &dbt, DB_SET)) != 0)
178                         goto err;
179         } else {
180                 if ((ret = __logc_get(logc, &lsn, &dbt, DB_LAST)) != 0)
181                         goto err;
182                 /*
183                  * Twiddle the last LSN so it points to the beginning of the
184                  * last file; we know there's no checkpoint after that, since
185                  * the log system already looked there.
186                  */
187                 lsn.offset = 0;
188         }
189
190         /* Read backwards, looking for checkpoints. */
191         while ((ret = __logc_get(logc, &lsn, &dbt, DB_PREV)) == 0) {
192                 if (dbt.size < sizeof(u_int32_t))
193                         continue;
194                 LOGCOPY_32(env, &rectype, dbt.data);
195                 if (rectype == DB___txn_ckp) {
196                         *lsnp = lsn;
197                         break;
198                 }
199         }
200
201 err:    if ((t_ret = __logc_close(logc)) != 0 && ret == 0)
202                 ret = t_ret;
203
204         /*
205          * Not finding a checkpoint is not an error;  there may not exist
206          * one in the log.
207          */
208         return ((ret == 0 || ret == DB_NOTFOUND) ? 0 : ret);
209 }
210
211 /*
212  * __txn_env_refresh --
213  *      Clean up after the transaction system on a close or failed open.
214  *
215  * PUBLIC: int __txn_env_refresh __P((ENV *));
216  */
217 int
218 __txn_env_refresh(env)
219         ENV *env;
220 {
221         DB_TXN *txn;
222         DB_TXNMGR *mgr;
223         REGINFO *reginfo;
224         u_int32_t txnid;
225         int aborted, ret, t_ret;
226
227         ret = 0;
228         mgr = env->tx_handle;
229         reginfo = &mgr->reginfo;
230
231         /*
232          * This function can only be called once per process (i.e., not
233          * once per thread), so no synchronization is required.
234          *
235          * The caller is probably doing something wrong if close is called with
236          * active transactions.  Try and abort any active transactions that are
237          * not prepared, but it's quite likely the aborts will fail because
238          * recovery won't find open files.  If we can't abort any of the
239          * unprepared transaction, panic, we have to run recovery to get back
240          * to a known state.
241          */
242         aborted = 0;
243         if (TAILQ_FIRST(&mgr->txn_chain) != NULL) {
244                 while ((txn = TAILQ_FIRST(&mgr->txn_chain)) != NULL) {
245                         /* Prepared transactions are OK. */
246                         txnid = txn->txnid;
247                         if (((TXN_DETAIL *)txn->td)->status == TXN_PREPARED) {
248                                 if ((ret = __txn_discard_int(txn, 0)) != 0) {
249                                         __db_err(env, ret,
250                                             "unable to discard txn %#lx",
251                                             (u_long)txnid);
252                                         break;
253                                 }
254                                 continue;
255                         }
256                         aborted = 1;
257                         if ((t_ret = __txn_abort(txn)) != 0) {
258                                 __db_err(env, t_ret,
259                                     "unable to abort transaction %#lx",
260                                     (u_long)txnid);
261                                 ret = __env_panic(env, t_ret);
262                                 break;
263                         }
264                 }
265                 if (aborted) {
266                         __db_errx(env,
267         "Error: closing the transaction region with active transactions");
268                         if (ret == 0)
269                                 ret = EINVAL;
270                 }
271         }
272
273         /* Discard the per-thread lock. */
274         if ((t_ret = __mutex_free(env, &mgr->mutex)) != 0 && ret == 0)
275                 ret = t_ret;
276
277         /* Detach from the region. */
278         if (F_ISSET(env, ENV_PRIVATE))
279                 reginfo->mtx_alloc = MUTEX_INVALID;
280         if ((t_ret = __env_region_detach(env, reginfo, 0)) != 0 && ret == 0)
281                 ret = t_ret;
282
283         __os_free(env, mgr);
284
285         env->tx_handle = NULL;
286         return (ret);
287 }
288
289 /*
290  * __txn_region_mutex_count --
291  *      Return the number of mutexes the txn region will need.
292  *
293  * PUBLIC: u_int32_t __txn_region_mutex_count __P((ENV *));
294  */
295 u_int32_t
296 __txn_region_mutex_count(env)
297         ENV *env;
298 {
299         DB_ENV *dbenv;
300
301         dbenv = env->dbenv;
302
303         /*
304          * We need a MVCC mutex for each TXN_DETAIL structure, a mutex for
305          * DB_TXNMGR structure, two mutexes for the DB_TXNREGION structure.
306          */
307         return (dbenv->tx_max + 1 + 2);
308 }
309
310 /*
311  * __txn_region_size --
312  *       Return the amount of space needed for the txn region.
313  */
314 static size_t
315 __txn_region_size(env)
316         ENV *env;
317 {
318         DB_ENV *dbenv;
319         size_t s;
320
321         dbenv = env->dbenv;
322
323         /*
324          * Make the region large enough to hold the primary transaction region
325          * structure, txn_max transaction detail structures, txn_max chunks of
326          * overhead required by the underlying shared region allocator for each
327          * chunk of memory, txn_max transaction names, at an average of 20
328          * bytes each, and 10KB for safety.
329          */
330         s = sizeof(DB_TXNREGION) +
331             dbenv->tx_max * (sizeof(TXN_DETAIL) + __env_alloc_overhead() + 20) +
332             10 * 1024;
333         return (s);
334 }
335
336 /*
337  * __txn_id_set --
338  *      Set the current transaction ID and current maximum unused ID (for
339  *      testing purposes only).
340  *
341  * PUBLIC: int __txn_id_set __P((ENV *, u_int32_t, u_int32_t));
342  */
343 int
344 __txn_id_set(env, cur_txnid, max_txnid)
345         ENV *env;
346         u_int32_t cur_txnid, max_txnid;
347 {
348         DB_TXNMGR *mgr;
349         DB_TXNREGION *region;
350         int ret;
351
352         ENV_REQUIRES_CONFIG(env, env->tx_handle, "txn_id_set", DB_INIT_TXN);
353
354         mgr = env->tx_handle;
355         region = mgr->reginfo.primary;
356         region->last_txnid = cur_txnid;
357         region->cur_maxid = max_txnid;
358
359         ret = 0;
360         if (cur_txnid < TXN_MINIMUM) {
361                 __db_errx(env, "Current ID value %lu below minimum",
362                     (u_long)cur_txnid);
363                 ret = EINVAL;
364         }
365         if (max_txnid < TXN_MINIMUM) {
366                 __db_errx(env, "Maximum ID value %lu below minimum",
367                     (u_long)max_txnid);
368                 ret = EINVAL;
369         }
370         return (ret);
371 }
372
373 /*
374  * __txn_oldest_reader --
375  *       Find the oldest "read LSN" of any active transaction'
376  *       MVCC changes older than this can safely be discarded from the cache.
377  *
378  * PUBLIC: int __txn_oldest_reader __P((ENV *, DB_LSN *));
379  */
380 int
381 __txn_oldest_reader(env, lsnp)
382         ENV *env;
383         DB_LSN *lsnp;
384 {
385         DB_LSN old_lsn;
386         DB_TXNMGR *mgr;
387         DB_TXNREGION *region;
388         TXN_DETAIL *td;
389         int ret;
390
391         if ((mgr = env->tx_handle) == NULL)
392                 return (0);
393         region = mgr->reginfo.primary;
394
395         if ((ret = __log_current_lsn(env, &old_lsn, NULL, NULL)) != 0)
396                 return (ret);
397
398         TXN_SYSTEM_LOCK(env);
399         SH_TAILQ_FOREACH(td, &region->active_txn, links, __txn_detail)
400                 if (LOG_COMPARE(&td->read_lsn, &old_lsn) < 0)
401                         old_lsn = td->read_lsn;
402
403         *lsnp = old_lsn;
404         TXN_SYSTEM_UNLOCK(env);
405
406         return (0);
407 }
408
409 /*
410  * __txn_add_buffer --
411  *      Add to the count of buffers created by the given transaction.
412  *
413  * PUBLIC: int __txn_add_buffer __P((ENV *, TXN_DETAIL *));
414  */
415 int
416 __txn_add_buffer(env, td)
417         ENV *env;
418         TXN_DETAIL *td;
419 {
420         DB_ASSERT(env, td != NULL);
421
422         MUTEX_LOCK(env, td->mvcc_mtx);
423         DB_ASSERT(env, td->mvcc_ref < UINT32_MAX);
424         ++td->mvcc_ref;
425         MUTEX_UNLOCK(env, td->mvcc_mtx);
426
427         COMPQUIET(env, NULL);
428         return (0);
429 }
430
431 /*
432  * __txn_remove_buffer --
433  *      Remove a buffer from a transaction -- free the transaction if necessary.
434  *
435  * PUBLIC: int __txn_remove_buffer __P((ENV *, TXN_DETAIL *, db_mutex_t));
436  */
437 int
438 __txn_remove_buffer(env, td, hash_mtx)
439         ENV *env;
440         TXN_DETAIL *td;
441         db_mutex_t hash_mtx;
442 {
443         DB_TXNMGR *mgr;
444         DB_TXNREGION *region;
445         int need_free, ret;
446
447         DB_ASSERT(env, td != NULL);
448         ret = 0;
449         mgr = env->tx_handle;
450         region = mgr->reginfo.primary;
451
452         MUTEX_LOCK(env, td->mvcc_mtx);
453         DB_ASSERT(env, td->mvcc_ref > 0);
454
455         /*
456          * We free the transaction detail here only if this is the last
457          * reference and td is on the list of committed snapshot transactions
458          * with active pages.
459          */
460         need_free = (--td->mvcc_ref == 0) && F_ISSET(td, TXN_DTL_SNAPSHOT);
461         MUTEX_UNLOCK(env, td->mvcc_mtx);
462
463         if (need_free) {
464                 MUTEX_UNLOCK(env, hash_mtx);
465
466                 ret = __mutex_free(env, &td->mvcc_mtx);
467                 td->mvcc_mtx = MUTEX_INVALID;
468
469                 TXN_SYSTEM_LOCK(env);
470                 SH_TAILQ_REMOVE(&region->mvcc_txn, td, links, __txn_detail);
471 #ifdef HAVE_STATISTICS
472                 --region->stat.st_nsnapshot;
473 #endif
474                 __env_alloc_free(&mgr->reginfo, td);
475                 TXN_SYSTEM_UNLOCK(env);
476
477                 MUTEX_READLOCK(env, hash_mtx);
478         }
479
480         return (ret);
481 }