00001 /* -*- mode:C++; c-basic-offset:4 -*- 00002 Shore-MT -- Multi-threaded port of the SHORE storage manager 00003 00004 Copyright (c) 2007-2009 00005 Data Intensive Applications and Systems Labaratory (DIAS) 00006 Ecole Polytechnique Federale de Lausanne 00007 00008 All Rights Reserved. 00009 00010 Permission to use, copy, modify and distribute this software and 00011 its documentation is hereby granted, provided that both the 00012 copyright notice and this permission notice appear in all copies of 00013 the software, derivative works or modified versions, and any 00014 portions thereof, and that both notices appear in supporting 00015 documentation. 00016 00017 This code is distributed in the hope that it will be useful, but 00018 WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS 00020 DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 00021 RESULTING FROM THE USE OF THIS SOFTWARE. 00022 */ 00023 00024 /*<std-header orig-src='shore' incl-file-exclusion='LOCK_S_H'> 00025 00026 $Id: lock_s.h,v 1.79 2012/01/02 17:02:17 nhall Exp $ 00027 00028 SHORE -- Scalable Heterogeneous Object REpository 00029 00030 Copyright (c) 1994-99 Computer Sciences Department, University of 00031 Wisconsin -- Madison 00032 All Rights Reserved. 00033 00034 Permission to use, copy, modify and distribute this software and its 00035 documentation is hereby granted, provided that both the copyright 00036 notice and this permission notice appear in all copies of the 00037 software, derivative works or modified versions, and any portions 00038 thereof, and that both notices appear in supporting documentation. 00039 00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY 00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS 00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND 00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 00044 00045 This software was developed with support by the Advanced Research 00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by 00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518. 00048 Further funding for this work was provided by DARPA through 00049 Rome Research Laboratory Contract No. F30602-97-2-0247. 00050 00051 */ 00052 00053 #ifndef LOCK_S_H 00054 #define LOCK_S_H 00055 00056 #include "w_defines.h" 00057 00058 /* -- do not edit anything above this line -- </std-header>*/ 00059 00060 #ifdef __GNUG__ 00061 #pragma interface 00062 #endif 00063 00064 /**\cond skip */ 00065 class lock_base_t : public smlevel_1 { 00066 public: 00067 // Their order is significant. 00068 00069 enum status_t { 00070 t_no_status = 0, 00071 t_granted = 1, 00072 t_converting = 2, 00073 t_waiting = 4 00074 }; 00075 00076 typedef smlevel_0::lock_mode_t lmode_t; 00077 00078 typedef smlevel_0::lock_duration_t duration_t; 00079 00080 enum { 00081 MIN_MODE = NL, MAX_MODE = EX, 00082 NUM_MODES = MAX_MODE - MIN_MODE + 1 00083 }; 00084 00085 static const char* const mode_str[NUM_MODES]; 00086 static const char* const duration_str[t_num_durations]; 00087 static const bool compat[NUM_MODES][NUM_MODES]; 00088 static const lmode_t supr[NUM_MODES][NUM_MODES]; 00089 }; 00090 /**\endcond skip */ 00091 00092 #ifndef LOCK_S 00093 /* 00094 typedef lock_base_t::duration_t lock_duration_t; 00095 // typedef lock_base_t::lmode_t lock_mode_t; lock_mode_t defined in basics.h 00096 typedef lock_base_t::status_t status_t; 00097 00098 #define LOCK_NL lock_base_t::NL 00099 #define LOCK_IS lock_base_t::IS 00100 #define LOCK_IX lock_base_t::IX 00101 #define LOCK_SH lock_base_t::SH 00102 #define LOCK_SIX lock_base_t::SIX 00103 #define LOCK_UD lock_base_t::UD 00104 #define LOCK_EX lock_base_t::EX 00105 00106 #define LOCK_INSTANT lock_base_t::t_instant 00107 #define LOCK_SHORT lock_base_t::t_short 00108 #define LOCK_MEDIUM lock_base_t::t_medium 00109 #define LOCK_LONG lock_base_t::t_long 00110 #define LOCK_VERY_LONG lock_base_t::t_very_long 00111 */ 00112 #endif 00113 00114 /**\brief The means of identifying a desired or held lock 00115 * 00116 * \details 00117 * Lock manager requests (acquire, release, query) take an argument 00118 * of this kind to identify the entity to be locked. Not all 00119 * lockids refer to anything extant. 00120 * 00121 * The structure of the lockid_t is such that several entity types 00122 * are inferred, and the lockid_t has constructors from these entities' 00123 * identifier classes, as well as methods to modify the lockid while 00124 * retaining its inferred-entity type. The enumerator type name_space_t 00125 * identifies the entity type of the lock_id, and is returned by the 00126 * method space: 00127 * 00128 * - t_vol : 00129 * - volume lock 00130 * - no parent in hierarchy 00131 * - constructed from vid_t 00132 * - can extract vid_t with vid() 00133 * 00134 * - t_store : 00135 * - store lock (file lock, index lock) 00136 * - parent in hierarchy is volume lock 00137 * - constructed from stid_t 00138 * - can extract snum_t with store() and vid_t with vid() 00139 * - can extract stid with extract_stid() 00140 * 00141 * - t_page : 00142 * - page lock 00143 * - parent in hierarchy is store lock 00144 * - constructed from lpid_t 00145 * - can extract shpid_t with page(), snum_t with store() and vid_t with vid() 00146 * - can extract stid with extract_stid() 00147 * - can extract lpid with extract_lpid() 00148 * 00149 * - t_kvl : 00150 * - key-value lock 00151 * - parent in hierarchy is store lock 00152 * - constructed from kvl_t (which is constructed from a vec_t : see 00153 * vec_t::make_kvl) 00154 * - can extract kvl_t with extract_kvl() 00155 * - can extract snum_t with store() and vid_t with vid() 00156 * - can extract stid with extract_stid() 00157 * 00158 * - t_record : 00159 * - lock on record in file 00160 * - parent in hierarchy is page lock 00161 * - constructed from rid_t 00162 * - can extract slotid_t with slot(), shpid_t with page(), 00163 * snum_t with store() and vid_t with vid() 00164 * - can extract rid_t with extract_rid() 00165 * - can extract stid with extract_stid() 00166 * - can extract lpid with extract_lpid() 00167 * 00168 * - t_extent : 00169 * - lock on extent 00170 * - not in a hierarchy 00171 * - constructed from extid_t 00172 * - can extract extnum_t with extent() 00173 * - can extract extid_t with extract_extent() 00174 * 00175 * - t_user1 : 00176 * - lock on user-defined entity 1 00177 * - not in a hierarchy 00178 * - constructed from user1_t 00179 * - can extract user1_t with extract_user1() 00180 * 00181 * - t_user2 : 00182 * - lock on user-defined entity 2 00183 * - parent in hierarchy is user-defined entity 1 00184 * - constructed from user2_t 00185 * - can extract user2_t with extract_user2() 00186 * - can extract user1_t with extract_user1() 00187 * 00188 * - t_user3 : 00189 * - lock on user-defined entity 3 00190 * - parent in hierarchy is user-defined entity 2 00191 * - constructed from user3_t 00192 * - can extract user3_t with extract_user3() 00193 * - can extract user2_t with extract_user2() 00194 * - can extract user1_t with extract_user1() 00195 * 00196 * - t_user4 : 00197 * - lock on user-defined entity 4 00198 * - parent in hierarchy is user-defined entity 3 00199 * - constructed from user4_t 00200 * - can extract user4_t with extract_user4() 00201 * - can extract user3_t with extract_user3() 00202 * - can extract user2_t with extract_user2() 00203 * - can extract user1_t with extract_user1() 00204 * 00205 * \attention The enumeration values of name_space_t have functional 00206 * significance; they are use to compute parents in the hierarchy, 00207 * so modify them with care! 00208 * 00209 * The user-defined entity types are for use by a server; they offer 00210 * a hierarchy. 00211 * 00212 */ 00213 class lockid_t { 00214 static w_hashing::uhash lockhashfunc; // in lock_core.cpp 00215 public: 00216 // 00217 // The lock graph consists of 6 nodes: volumes, stores, pages, key values, 00218 // records, and extents. The first 5 of these form a tree of 4 levels. 00219 // The node for extents is not connected to the rest. The name_space_t 00220 // enumerator maps node types to integers. These numbers are used for 00221 // indexing into arrays containing node type specific info per entry (e.g 00222 // the lock caches for volumes, stores, and pages). 00223 // 00224 /**\cond skip */ 00225 enum { NUMNODES = 6 }; 00226 // The per-xct cache only caches volume, store, and page locks. 00227 enum { NUMLEVELS = 4 }; 00228 /**\endcond skip */ 00229 00230 enum name_space_t { // you cannot change these values with impunity 00231 t_bad = 10, 00232 t_vol = 0, 00233 t_store = 1, // parent is 1/2 = 0 t_vol 00234 t_page = 2, // parent is 2/2 = 1 t_store 00235 t_kvl = 3, // parent is 3/2 = 1 t_store 00236 t_record = 4, // parent is 4/2 = 2 t_page 00237 t_extent = 5, 00238 t_user1 = 6, 00239 t_user2 = 7, // parent is t_user1 00240 t_user3 = 8, // parent is t_user2 00241 t_user4 = 9 // parent is t_user3 00242 }; 00243 00244 static const int cached_granularity = t_page; 00245 00246 typedef uint4_t page_bits_t; 00247 00248 /**\brief User-defined entity 1 */ 00249 struct user1_t { 00250 uint2_t u1; 00251 user1_t() : u1(0) {} 00252 user1_t(uint2_t v1) : u1(v1) {} 00253 }; 00254 00255 /**\brief User-defined entity 2 */ 00256 struct user2_t : public user1_t { 00257 uint4_t u2; 00258 user2_t() : u2(0) {} 00259 user2_t(uint2_t v1, uint4_t v2): user1_t(v1), u2(v2) {} 00260 }; 00261 00262 /**\brief User-defined entity 3 */ 00263 struct user3_t : public user2_t { 00264 uint4_t u3; 00265 user3_t() : u3(0) {} 00266 user3_t(uint2_t v1, uint4_t v2, uint4_t v3) 00267 : user2_t(v1, v2), u3(v3) {} 00268 }; 00269 00270 /**\brief User-defined entity 4 */ 00271 struct user4_t : public user3_t { 00272 uint4_t u4; 00273 user4_t() : u4(0) {} 00274 user4_t(uint2_t v1, uint4_t v2, uint4_t v3, uint4_t v4) 00275 : user3_t(v1, v2, v3), u4(v4) {} 00276 }; 00277 00278 enum { pageWindex=2, slotWindex=3, user4Windex=3 }; 00279 enum { pageSindex=4, slotSindex=6, user4Sindex=6 }; 00280 00281 private: 00282 union { 00283 // 00284 w_base_t::uint8_t l[2]; 00285 // l[0,1] are just to support the hash function. 00286 00287 w_base_t::uint4_t w[4]; 00288 // w[0] == s[0,1] see below 00289 // w[1] == store or extent or user2 00290 // w[2] == page or user3 00291 // w[3] contains slot (in both s[6] and s[7]) or user4 00292 w_base_t::uint2_t s[8]; 00293 // s[0] high byte == lspace (lock type) 00294 // s[0] low byte == boolean used for extent-not-freeable 00295 // s[1] vol or user1 00296 // s[2,3]==w[1] 00297 // s[4,5]== w[2] see above 00298 // s[6] == slot 00299 // s[7] == slot copy 00300 }; 00301 00302 public: 00303 /**\brief comparison operator for lockid_t, used by lock manager */ 00304 bool operator<(lockid_t const &p) const; 00305 /**\brief equality operator for lockid_t*/ 00306 bool operator==(const lockid_t& p) const; 00307 /**\brief inequality operator for lockid_t*/ 00308 bool operator!=(const lockid_t& p) const; 00309 friend ostream& operator<<(ostream& o, const lockid_t& i); 00310 public: 00311 /// Used by lock cache 00312 uint4_t hash() const; // used by lock_cache 00313 /// clear out the lockid - initialize to mean nothing 00314 void zero(); 00315 00316 private: 00317 00318 // 00319 // lspace -- contains enum for type of lockid_t 00320 // 00321 public: 00322 /// return the kind of entity this describes 00323 name_space_t lspace() const; 00324 private: 00325 void set_lspace(lockid_t::name_space_t value); 00326 uint1_t lspace_bits() const; 00327 00328 // 00329 // vid - volume 00330 // 00331 public: 00332 /// extract volume id lockid whose lspace() == t_vol or has parent with lspace() == t_vol 00333 vid_t vid() const; 00334 private: 00335 void set_vid(const vid_t & v); 00336 uint2_t vid_bits() const; 00337 00338 // 00339 // store - stid 00340 // 00341 public: 00342 /// extract store number lockid whose lspace() == t_store or has parent with lspace() == t_store 00343 const snum_t& store() const; 00344 private: 00345 void set_snum(const snum_t & s); 00346 void set_store(const stid_t & s); 00347 uint4_t store_bits() const; 00348 00349 // 00350 // extent -- used only when lspace() == t_extent 00351 // 00352 public: 00353 /// extract extent number lockid whose lspace() == t_extent 00354 const extnum_t& extent() const; 00355 private: 00356 void set_extent(const extnum_t & e); 00357 uint4_t extent_bits() const; 00358 00359 // 00360 // page id 00361 // 00362 public: 00363 /// extract short page number lockid whose lspace() == t_page or has parent with lspace()==t_page 00364 const shpid_t& page() const; 00365 private: 00366 void set_page(const shpid_t & p); 00367 uint4_t page_bits() const ; 00368 void set_page_bits(lockid_t::page_bits_t); 00369 // 00370 // slot id 00371 // 00372 public: 00373 /// extract slot number lockid whose lspace() == t_record 00374 slotid_t slot() const; 00375 private: 00376 void set_slot(const slotid_t & e); 00377 uint2_t slot_bits() const; 00378 uint4_t slot_kvl_bits() const; 00379 00380 // 00381 // user1 00382 // 00383 public: 00384 /// extract uint2_t from whose lspace() == t_user1 00385 uint2_t u1() const; 00386 private: 00387 void set_u1(uint2_t i); 00388 00389 // 00390 // user2 00391 // 00392 public: 00393 /// extract uint4_t from whose lspace() == t_user2 00394 uint4_t u2() const; 00395 private: 00396 void set_u2(uint4_t i); 00397 00398 // 00399 // user3 00400 // 00401 public: 00402 /// extract uint4_t from whose lspace() == t_user3 00403 uint4_t u3() const; 00404 private: 00405 void set_u3(uint4_t i); 00406 00407 // 00408 // user4 00409 // 00410 public: 00411 /// extract uint4_t from whose lspace() == t_user4 00412 uint4_t u4() const; 00413 private: 00414 void set_u4(uint4_t i); 00415 00416 public: 00417 00418 /**\brief for extent locks only, used by volume manager 00419 * \details 00420 * \anchor FREEEXTLOCK 00421 * Set to true when the extent contains an uncommitted allocated page. 00422 * This is done when a page is allocated in the extent; it is used 00423 * for special handling of extent locks in the lock manager. 00424 * 00425 * The special handling requires a little background: 00426 * 00427 * - extent locks are not in the hierarchy 00428 * - extent IX locks are acquired when a page in the extent is allocated 00429 * (or recovered, in recovery case) 00430 * - extent IX locks are acquired when a page in the extent is freed 00431 * - extent IX locks are acquired when allocating the extent to a store 00432 * - extent EX locks are acquired when deallocating all the extents in 00433 * a store (destroying the store), at which time we have an EX lock on 00434 * the store. 00435 * 00436 * - We need some way to tell when an extent can be freed. It can be 00437 * freed when there are no pages allocated in the extent. 00438 * Presumably we would have any transaction that deallocated a page 00439 * in the extent try to deallocate the extent (i.e., if there are 00440 * no more pages in the extent). But it doesn't acquire an EX lock 00441 * on the extent, so another transaction could slip in and allocate 00442 * pages in the extent. 00443 * - If the transaction (that deleted one or more pages in an extent) 00444 * tries to deallocate the extent at the transaction end, it would 00445 * have to inspect the extent link to tell if the extent has no 00446 * pages in it, and it would still have to do something to avoid races 00447 * with other transactions. 00448 * 00449 * The special handling is this: 00450 * - Transactions that allocate pages in an extent set the bit in the 00451 * \b lock saying there are pages allocated in the extent. 00452 * - Transactions that deallocate pages in an extent clear the bit in the 00453 * \b lock when there are no more pages allocated in the extent. 00454 * - This bypasses a page fix for inspecting the extlink_t. 00455 * - Synchronization for this bit in the lockid is provided by the 00456 * volume manager; the bit is set and cleared only in the volume manager, 00457 * which is a monitor. 00458 * - At transaction end, a transaction that has an IX lock on an 00459 * extent tries to upgrade it to an EX if the extent lock indicates 00460 * that no pages are allocated in the extent. If it succeeds, 00461 * the lock manager can delete the extent while holding the EX lock, 00462 * then free the lock. 00463 * 00464 * When at the end of transaction, lock_m::release_duration() is 00465 * called, the lock manager returns eFOUNDEXTTOFREE when it encounters 00466 * an extent lock with this bit set. 00467 * 00468 */ 00469 void set_ext_has_page_alloc(bool value); 00470 /**\brief for extent locks only, used by lock manager 00471 * \details 00472 * Returns true when the extent contains an uncommitted allocated page. 00473 * See discussion in set_ext_has_page_alloc, above. 00474 */ 00475 bool ext_has_page_alloc() const ; 00476 00477 // construct vacuous lockid_t 00478 NORET lockid_t() ; 00479 /// construct from volume id 00480 NORET lockid_t(const vid_t& vid); 00481 /// construct from full extent id 00482 NORET lockid_t(const extid_t& extid); 00483 /// construct from full store id 00484 NORET lockid_t(const stid_t& stid); 00485 /// construct from full page id 00486 NORET lockid_t(const lpid_t& lpid); 00487 /// construct from full record id 00488 NORET lockid_t(const rid_t& rid); 00489 /// construct from kvl_t (hash of key,value, from vec_t) 00490 NORET lockid_t(const kvl_t& kvl); 00491 /// copy constructor 00492 NORET lockid_t(const lockid_t& i); 00493 /// construct from user1_t 00494 NORET lockid_t(const user1_t& u); 00495 /// construct from user2_t 00496 NORET lockid_t(const user2_t& u); 00497 /// construct from user3_t 00498 NORET lockid_t(const user3_t& u); 00499 /// construct from user4_t 00500 NORET lockid_t(const user4_t& u); 00501 00502 /// extract a full extent id from an extent lock 00503 void extract_extent(extid_t &e) const; 00504 /// extract a full store id from a store, page, or record lock 00505 void extract_stid(stid_t &s) const; 00506 /// extract a full page id from a page or record lock 00507 void extract_lpid(lpid_t &p) const; 00508 /// extract a full record id from a record lock 00509 void extract_rid(rid_t &r) const; 00510 /// extract a kvl_t (hash of key,value) from a key-value lock 00511 void extract_kvl(kvl_t &k) const; 00512 /// extract a user1_t from user-defined entity 1, 2, 3, or 4 00513 void extract_user1(user1_t &u) const; 00514 /// extract a user2_t from user-defined entity 2, 3, or 4 00515 void extract_user2(user2_t &u) const; 00516 /// extract a user3_t from user-defined entity 3 or 4 00517 void extract_user3(user3_t &u) const; 00518 /// extract a user3_t from user-defined entity 4 00519 void extract_user4(user4_t &u) const; 00520 00521 /// Return true if type is t_user1, t_user2, t_user3 or t_user4 00522 bool is_user_lock() const; 00523 00524 /**\brief Nullify all parts of the lockid that apply to children in 00525 * the hierarchy. 00526 * 00527 * If the given space isn't in the hierarchy, this generates a fatal error. 00528 */ 00529 w_rc_t truncate(name_space_t space); 00530 w_rc_t make_parent(); 00531 00532 /// copy operator 00533 lockid_t& operator=(const lockid_t& i); 00534 00535 }; 00536 00537 /** \example lockid_test.cpp*/ 00538 00539 ostream& operator<<(ostream& o, const lockid_t::user1_t& u); 00540 ostream& operator<<(ostream& o, const lockid_t::user2_t& u); 00541 ostream& operator<<(ostream& o, const lockid_t::user3_t& u); 00542 ostream& operator<<(ostream& o, const lockid_t::user4_t& u); 00543 00544 istream& operator>>(istream& o, lockid_t::user1_t& u); 00545 istream& operator>>(istream& o, lockid_t::user2_t& u); 00546 istream& operator>>(istream& o, lockid_t::user3_t& u); 00547 istream& operator>>(istream& o, lockid_t::user4_t& u); 00548 00549 00550 00551 #if W_DEBUG_LEVEL>0 00552 #else 00553 #include "lock_s_inline.h" 00554 #endif 00555 00556 /*<std-footer incl-file-exclusion='LOCK_S_H'> -- do not edit anything below this line -- */ 00557 00558 #endif /*</std-footer>*/