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 //
init(TOKUTXN root)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 
destroy()62 void txn_child_manager::destroy() {
63     toku_mutex_destroy(&m_mutex);
64 }
65 
start_child_txn_for_recovery(TOKUTXN child,TOKUTXN parent,TXNID_PAIR txnid)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 
start_child_txn(TOKUTXN child,TOKUTXN parent)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 
finish_child_txn(TOKUTXN child)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 
suspend()109 void txn_child_manager::suspend() {
110     toku_mutex_lock(&m_mutex);
111 }
112 
resume()113 void txn_child_manager::resume() {
114     toku_mutex_unlock(&m_mutex);
115 }
116 
find_tokutxn_by_xid_unlocked(TXNID_PAIR xid,TOKUTXN * result)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 
iterate(txn_mgr_iter_callback cb,void * extra)129 int txn_child_manager::iterate(txn_mgr_iter_callback cb, void* extra) {
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