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