1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #include "ft/logger/log-internal.h" |
40 | #include "ft/txn/txn_child_manager.h" |
41 | |
42 | toku_instr_key *txn_child_manager_mutex_key; |
43 | |
44 | // |
45 | // initialized a txn_child_manager, |
46 | // when called, root->txnid.parent_id64 may not yet be set |
47 | // |
48 | void txn_child_manager::init(TOKUTXN root) { |
49 | invariant(root->txnid.child_id64 == TXNID_NONE); |
50 | invariant(root->parent == NULL); |
51 | m_root = root; |
52 | m_last_xid = TXNID_NONE; |
53 | ZERO_STRUCT(m_mutex); |
54 | |
55 | toku_pthread_mutexattr_t attr; |
56 | toku_mutexattr_init(&attr); |
57 | toku_mutexattr_settype(&attr, TOKU_MUTEX_ADAPTIVE); |
58 | toku_mutex_init(*txn_child_manager_mutex_key, &m_mutex, &attr); |
59 | toku_mutexattr_destroy(&attr); |
60 | } |
61 | |
62 | void txn_child_manager::destroy() { |
63 | toku_mutex_destroy(&m_mutex); |
64 | } |
65 | |
66 | void txn_child_manager::start_child_txn_for_recovery(TOKUTXN child, TOKUTXN parent, TXNID_PAIR txnid) { |
67 | invariant(parent->txnid.parent_id64 == m_root->txnid.parent_id64); |
68 | invariant(txnid.parent_id64 == m_root->txnid.parent_id64); |
69 | |
70 | child->txnid = txnid; |
71 | toku_mutex_lock(&m_mutex); |
72 | if (txnid.child_id64 > m_last_xid) { |
73 | m_last_xid = txnid.child_id64; |
74 | } |
75 | parent->child = child; |
76 | toku_mutex_unlock(&m_mutex); |
77 | } |
78 | |
79 | void txn_child_manager::start_child_txn(TOKUTXN child, TOKUTXN parent) { |
80 | invariant(parent->txnid.parent_id64 == m_root->txnid.parent_id64); |
81 | child->txnid.parent_id64 = m_root->txnid.parent_id64; |
82 | toku_mutex_lock(&m_mutex); |
83 | |
84 | ++m_last_xid; |
85 | // Here we ensure that the child_id64 is never equal to the parent_id64 |
86 | // We do this to make this feature work more easily with the XIDs |
87 | // struct and message application. The XIDs struct stores the parent id |
88 | // as the first TXNID, and subsequent TXNIDs store child ids. So, if we |
89 | // have a case where the parent id is the same as the child id, we will |
90 | // have to do some tricky maneuvering in the message application code |
91 | // in ule.cc. So, to lessen the probability of bugs, we ensure that the |
92 | // parent id is not the same as the child id. |
93 | if (m_last_xid == m_root->txnid.parent_id64) { |
94 | ++m_last_xid; |
95 | } |
96 | child->txnid.child_id64 = m_last_xid; |
97 | |
98 | parent->child = child; |
99 | toku_mutex_unlock(&m_mutex); |
100 | } |
101 | |
102 | void txn_child_manager::finish_child_txn(TOKUTXN child) { |
103 | invariant(child->txnid.parent_id64 == m_root->txnid.parent_id64); |
104 | toku_mutex_lock(&m_mutex); |
105 | child->parent->child = NULL; |
106 | toku_mutex_unlock(&m_mutex); |
107 | } |
108 | |
109 | void txn_child_manager::suspend() { |
110 | toku_mutex_lock(&m_mutex); |
111 | } |
112 | |
113 | void txn_child_manager::resume() { |
114 | toku_mutex_unlock(&m_mutex); |
115 | } |
116 | |
117 | void txn_child_manager::find_tokutxn_by_xid_unlocked(TXNID_PAIR xid, TOKUTXN* result) { |
118 | invariant(xid.parent_id64 == m_root->txnid.parent_id64); |
119 | TOKUTXN curr_txn = m_root; |
120 | while (curr_txn != NULL) { |
121 | if (xid.child_id64 == curr_txn->txnid.child_id64) { |
122 | *result = curr_txn; |
123 | break; |
124 | } |
125 | curr_txn = curr_txn->child; |
126 | } |
127 | } |
128 | |
129 | int txn_child_manager::iterate(txn_mgr_iter_callback cb, void* ) { |
130 | TOKUTXN curr_txn = m_root; |
131 | int ret = 0; |
132 | toku_mutex_lock(&m_mutex); |
133 | while (curr_txn != NULL) { |
134 | ret = cb(curr_txn, extra); |
135 | if (ret != 0) { |
136 | break; |
137 | } |
138 | curr_txn = curr_txn->child; |
139 | } |
140 | toku_mutex_unlock(&m_mutex); |
141 | return ret; |
142 | } |
143 | |
144 | |