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 38 Licensed under the Apache License, Version 2.0 (the "License"); 39 you may not use this file except in compliance with the License. 40 You may obtain a copy of the License at 41 42 http://www.apache.org/licenses/LICENSE-2.0 43 44 Unless required by applicable law or agreed to in writing, software 45 distributed under the License is distributed on an "AS IS" BASIS, 46 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 See the License for the specific language governing permissions and 48 limitations under the License. 49 ======= */ 50 51 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." 52 53 #pragma once 54 55 #include <db.h> 56 57 #include "portability/toku_pthread.h" 58 59 #include "locktree/locktree.h" 60 #include "locktree/txnid_set.h" 61 #include "locktree/wfg.h" 62 #include "ft/comparator.h" 63 64 namespace toku { 65 66 // A lock request contains the db, the key range, the lock type, and 67 // the transaction id that describes a potential row range lock. 68 // 69 // the typical use case is: 70 // - initialize a lock request 71 // - start to try to acquire the lock 72 // - do something else 73 // - wait for the lock request to be resolved on a timed condition 74 // - destroy the lock request 75 // a lock request is resolved when its state is no longer pending, or 76 // when it becomes granted, or timedout, or deadlocked. when resolved, the 77 // state of the lock request is changed and any waiting threads are awakened. 78 79 class lock_request { 80 public: 81 enum type { 82 UNKNOWN, 83 READ, 84 WRITE 85 }; 86 87 // effect: Initializes a lock request. 88 void create(void); 89 90 // effect: Destroys a lock request. 91 void destroy(void); 92 void clearmem(char c); 93 94 // effect: Resets the lock request parameters, allowing it to be reused. 95 // requires: Lock request was already created at some point 96 void set(locktree *lt, TXNID txnid, const DBT *left_key, const DBT *right_key, type lock_type, bool big_txn, void *extra = nullptr); 97 98 // effect: Tries to acquire a lock described by this lock request. 99 // returns: The return code of locktree::acquire_[write,read]_lock() 100 // or DB_LOCK_DEADLOCK if this request would end up deadlocked. 101 int start(void); 102 103 // effect: Sleeps until either the request is granted or the wait time expires. 104 // returns: The return code of locktree::acquire_[write,read]_lock() 105 // or simply DB_LOCK_NOTGRANTED if the wait time expired. 106 int wait(uint64_t wait_time_ms); 107 int wait(uint64_t wait_time_ms, uint64_t killed_time_ms, int (*killed_callback)(void)); 108 109 // return: left end-point of the lock range 110 const DBT *get_left_key(void) const; 111 112 // return: right end-point of the lock range 113 const DBT *get_right_key(void) const; 114 115 // return: the txnid waiting for a lock 116 TXNID get_txnid(void) const; 117 118 // return: when this lock request started, as milliseconds from epoch 119 uint64_t get_start_time(void) const; 120 121 // return: which txnid is blocking this request (there may be more, though) 122 TXNID get_conflicting_txnid(void) const; 123 124 // effect: Retries all of the lock requests for the given locktree. 125 // Any lock requests successfully restarted is completed and woken 126 // up. 127 // The rest remain pending. 128 static void retry_all_lock_requests( 129 locktree *lt, 130 void (*after_retry_test_callback)(void) = nullptr); 131 static void retry_all_lock_requests_info(lt_lock_request_info *info); 132 133 void set_start_test_callback(void (*f)(void)); 134 void set_start_before_pending_test_callback(void (*f)(void)); 135 void set_retry_test_callback(void (*f)(void)); 136 137 void *get_extra(void) const; 138 139 void kill_waiter(void); 140 static void kill_waiter(locktree *lt, void *extra); 141 142 private: 143 enum state { 144 UNINITIALIZED, 145 INITIALIZED, 146 PENDING, 147 COMPLETE, 148 DESTROYED, 149 }; 150 151 // The keys for a lock request are stored "unowned" in m_left_key 152 // and m_right_key. When the request is about to go to sleep, it 153 // copies these keys and stores them in m_left_key_copy etc and 154 // sets the temporary pointers to null. 155 TXNID m_txnid; 156 TXNID m_conflicting_txnid; 157 uint64_t m_start_time; 158 const DBT *m_left_key; 159 const DBT *m_right_key; 160 DBT m_left_key_copy; 161 DBT m_right_key_copy; 162 163 // The lock request type and associated locktree 164 type m_type; 165 locktree *m_lt; 166 167 // If the lock request is in the completed state, then its 168 // final return value is stored in m_complete_r 169 int m_complete_r; 170 state m_state; 171 172 toku_cond_t m_wait_cond; 173 174 bool m_big_txn; 175 176 // the lock request info state stored in the 177 // locktree that this lock request is for. 178 struct lt_lock_request_info *m_info; 179 180 void *m_extra; 181 182 // effect: tries again to acquire the lock described by this lock request 183 // returns: 0 if retrying the request succeeded and is now complete 184 int retry(void); 185 186 void complete(int complete_r); 187 188 // effect: Finds another lock request by txnid. 189 // requires: The lock request info mutex is held 190 lock_request *find_lock_request(const TXNID &txnid); 191 192 // effect: Insert this lock request into the locktree's set. 193 // requires: the locktree's mutex is held 194 void insert_into_lock_requests(void); 195 196 // effect: Removes this lock request from the locktree's set. 197 // requires: The lock request info mutex is held 198 void remove_from_lock_requests(void); 199 200 // effect: Asks this request's locktree which txnids are preventing 201 // us from getting the lock described by this request. 202 // returns: conflicts is populated with the txnid's that this request 203 // is blocked on 204 void get_conflicts(txnid_set *conflicts); 205 206 // effect: Builds a wait-for-graph for this lock request and the given conflict set 207 void build_wait_graph(wfg *wait_graph, const txnid_set &conflicts); 208 209 // returns: True if this lock request is in deadlock with the given conflicts set 210 bool deadlock_exists(const txnid_set &conflicts); 211 212 void copy_keys(void); 213 214 static int find_by_txnid(lock_request *const &request, const TXNID &txnid); 215 216 void (*m_start_test_callback)(void); 217 void (*m_start_before_pending_test_callback)(void); 218 void (*m_retry_test_callback)(void); 219 220 friend class lock_request_unit_test; 221 }; 222 ENSURE_POD(lock_request); 223 224 } /* namespace toku */ 225