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 void (*lock_wait_callback)(void *, TXNID, TXNID) = nullptr); 109 110 // return: left end-point of the lock range 111 const DBT *get_left_key(void) const; 112 113 // return: right end-point of the lock range 114 const DBT *get_right_key(void) const; 115 116 // return: the txnid waiting for a lock 117 TXNID get_txnid(void) const; 118 119 // return: when this lock request started, as milliseconds from epoch 120 uint64_t get_start_time(void) const; 121 122 // return: which txnid is blocking this request (there may be more, though) 123 TXNID get_conflicting_txnid(void) const; 124 125 // effect: Retries all of the lock requests for the given locktree. 126 // Any lock requests successfully restarted is completed and woken 127 // up. 128 // The rest remain pending. 129 static void retry_all_lock_requests( 130 locktree *lt, 131 void (*lock_wait_callback)(void *, TXNID, TXNID) = nullptr, 132 void (*after_retry_test_callback)(void) = nullptr); 133 static void retry_all_lock_requests_info(lt_lock_request_info *info, GrowableArray<TXNID> *collector); 134 135 void set_start_test_callback(void (*f)(void)); 136 void set_start_before_pending_test_callback(void (*f)(void)); 137 void set_retry_test_callback(void (*f)(void)); 138 139 void *get_extra(void) const; 140 141 void kill_waiter(void); 142 static void kill_waiter(locktree *lt, void *extra); 143 144 private: 145 enum state { 146 UNINITIALIZED, 147 INITIALIZED, 148 PENDING, 149 COMPLETE, 150 DESTROYED, 151 }; 152 153 // The keys for a lock request are stored "unowned" in m_left_key 154 // and m_right_key. When the request is about to go to sleep, it 155 // copies these keys and stores them in m_left_key_copy etc and 156 // sets the temporary pointers to null. 157 TXNID m_txnid; 158 TXNID m_conflicting_txnid; 159 uint64_t m_start_time; 160 const DBT *m_left_key; 161 const DBT *m_right_key; 162 DBT m_left_key_copy; 163 DBT m_right_key_copy; 164 165 // The lock request type and associated locktree 166 type m_type; 167 locktree *m_lt; 168 169 // If the lock request is in the completed state, then its 170 // final return value is stored in m_complete_r 171 int m_complete_r; 172 state m_state; 173 174 toku_cond_t m_wait_cond; 175 176 bool m_big_txn; 177 178 // the lock request info state stored in the 179 // locktree that this lock request is for. 180 struct lt_lock_request_info *m_info; 181 182 void *m_extra; 183 184 // effect: tries again to acquire the lock described by this lock request 185 // returns: 0 if retrying the request succeeded and is now complete 186 int retry(GrowableArray<TXNID> *conflict_collector); 187 188 void complete(int complete_r); 189 190 // effect: Finds another lock request by txnid. 191 // requires: The lock request info mutex is held 192 lock_request *find_lock_request(const TXNID &txnid); 193 194 // effect: Insert this lock request into the locktree's set. 195 // requires: the locktree's mutex is held 196 void insert_into_lock_requests(void); 197 198 // effect: Removes this lock request from the locktree's set. 199 // requires: The lock request info mutex is held 200 void remove_from_lock_requests(void); 201 202 // effect: Asks this request's locktree which txnids are preventing 203 // us from getting the lock described by this request. 204 // returns: conflicts is populated with the txnid's that this request 205 // is blocked on 206 void get_conflicts(txnid_set *conflicts); 207 208 // effect: Builds a wait-for-graph for this lock request and the given conflict set 209 void build_wait_graph(wfg *wait_graph, const txnid_set &conflicts); 210 211 // returns: True if this lock request is in deadlock with the given conflicts set 212 bool deadlock_exists(const txnid_set &conflicts); 213 214 void copy_keys(void); 215 216 static int find_by_txnid(lock_request *const &request, const TXNID &txnid); 217 218 // Report list of conflicts to lock wait callback. 219 static void report_waits(GrowableArray<TXNID> *wait_conflicts, 220 void (*lock_wait_callback)(void *, TXNID, TXNID)); 221 void add_conflicts_to_waits(txnid_set *conflicts, GrowableArray<TXNID> *wait_conflicts); 222 223 void (*m_start_test_callback)(void); 224 void (*m_start_before_pending_test_callback)(void); 225 void (*m_retry_test_callback)(void); 226 227 friend class lock_request_unit_test; 228 }; 229 ENSURE_POD(lock_request); 230 231 } /* namespace toku */ 232