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.76 2010/06/23 23:44:29 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 public: 00215 // 00216 // The lock graph consists of 6 nodes: volumes, stores, pages, key values, 00217 // records, and extents. The first 5 of these form a tree of 4 levels. 00218 // The node for extents is not connected to the rest. The name_space_t 00219 // enumerator maps node types to integers. These numbers are used for 00220 // indexing into arrays containing node type specific info per entry (e.g 00221 // the lock caches for volumes, stores, and pages). 00222 // 00223 /**\cond skip */ 00224 enum { NUMNODES = 6 }; 00225 // The per-xct cache only caches volume, store, and page locks. 00226 enum { NUMLEVELS = 4 }; 00227 /**\endcond skip */ 00228 00229 enum name_space_t { // you cannot change these values with impunity 00230 t_bad = 10, 00231 t_vol = 0, 00232 t_store = 1, // parent is 1/2 = 0 t_vol 00233 t_page = 2, // parent is 2/2 = 1 t_store 00234 t_kvl = 3, // parent is 3/2 = 1 t_store 00235 t_record = 4, // parent is 4/2 = 2 t_page 00236 t_extent = 5, 00237 t_user1 = 6, 00238 t_user2 = 7, // parent is t_user1 00239 t_user3 = 8, // parent is t_user2 00240 t_user4 = 9 // parent is t_user3 00241 }; 00242 00243 static const int cached_granularity = t_page; 00244 00245 typedef uint4_t page_bits_t; 00246 00247 /**\brief User-defined entity 1 */ 00248 struct user1_t { 00249 uint2_t u1; 00250 user1_t() : u1(0) {} 00251 user1_t(uint2_t v1) : u1(v1) {} 00252 }; 00253 00254 /**\brief User-defined entity 2 */ 00255 struct user2_t : public user1_t { 00256 uint4_t u2; 00257 user2_t() : u2(0) {} 00258 user2_t(uint2_t v1, uint4_t v2): user1_t(v1), u2(v2) {} 00259 }; 00260 00261 /**\brief User-defined entity 3 */ 00262 struct user3_t : public user2_t { 00263 uint4_t u3; 00264 user3_t() : u3(0) {} 00265 user3_t(uint2_t v1, uint4_t v2, uint4_t v3) 00266 : user2_t(v1, v2), u3(v3) {} 00267 }; 00268 00269 /**\brief User-defined entity 4 */ 00270 struct user4_t : public user3_t { 00271 uint4_t u4; 00272 user4_t() : u4(0) {} 00273 user4_t(uint2_t v1, uint4_t v2, uint4_t v3, uint4_t v4) 00274 : user3_t(v1, v2, v3), u4(v4) {} 00275 }; 00276 00277 enum { pageWindex=2, slotWindex=3, user4Windex=3 }; 00278 enum { pageSindex=4, slotSindex=6, user4Sindex=6 }; 00279 00280 private: 00281 union { 00282 // 00283 w_base_t::uint8_t l[2]; 00284 // l[0,1] are just to support the hash function. 00285 00286 w_base_t::uint4_t w[4]; 00287 // w[0] == s[0,1] see below 00288 // w[1] == store or extent or user2 00289 // w[2] == page or user3 00290 // w[3] contains slot (in both s[6] and s[7]) or user4 00291 w_base_t::uint2_t s[8]; 00292 // s[0] high byte == lspace (lock type) 00293 // s[0] low byte == boolean used for extent-not-freeable 00294 // s[1] vol or user1 00295 // s[2,3]==w[1] 00296 // s[4,5]== w[2] see above 00297 // s[6] == slot 00298 // s[7] == slot copy 00299 }; 00300 00301 public: 00302 /**\brief comparison operator for lockid_t, used by lock manager */ 00303 bool operator<(lockid_t const &p) const; 00304 /**\brief equality operator for lockid_t*/ 00305 bool operator==(const lockid_t& p) const; 00306 /**\brief inequality operator for lockid_t*/ 00307 bool operator!=(const lockid_t& p) const; 00308 friend ostream& operator<<(ostream& o, const lockid_t& i); 00309 public: 00310 /// Used by lock cache 00311 uint4_t hash() const; // used by lock_cache 00312 /// clear out the lockid - initialize to mean nothing 00313 void zero(); 00314 00315 private: 00316 00317 // 00318 // lspace -- contains enum for type of lockid_t 00319 // 00320 public: 00321 /// return the kind of entity this describes 00322 name_space_t lspace() const; 00323 private: 00324 void set_lspace(lockid_t::name_space_t value); 00325 uint1_t lspace_bits() const; 00326 00327 // 00328 // vid - volume 00329 // 00330 public: 00331 /// extract volume id lockid whose lspace() == t_vol or has parent with lspace() == t_vol 00332 vid_t vid() const; 00333 private: 00334 void set_vid(const vid_t & v); 00335 uint2_t vid_bits() const; 00336 00337 // 00338 // store - stid 00339 // 00340 public: 00341 /// extract store number lockid whose lspace() == t_store or has parent with lspace() == t_store 00342 const snum_t& store() const; 00343 private: 00344 void set_snum(const snum_t & s); 00345 void set_store(const stid_t & s); 00346 uint4_t store_bits() const; 00347 00348 // 00349 // extent -- used only when lspace() == t_extent 00350 // 00351 public: 00352 /// extract extent number lockid whose lspace() == t_extent 00353 const extnum_t& extent() const; 00354 private: 00355 void set_extent(const extnum_t & e); 00356 uint4_t extent_bits() const; 00357 00358 // 00359 // page id 00360 // 00361 public: 00362 /// extract short page number lockid whose lspace() == t_page or has parent with lspace()==t_page 00363 const shpid_t& page() const; 00364 private: 00365 void set_page(const shpid_t & p); 00366 uint4_t page_bits() const ; 00367 void set_page_bits(lockid_t::page_bits_t); 00368 // 00369 // slot id 00370 // 00371 public: 00372 /// extract slot number lockid whose lspace() == t_record 00373 slotid_t slot() const; 00374 private: 00375 void set_slot(const slotid_t & e); 00376 uint2_t slot_bits() const; 00377 uint4_t slot_kvl_bits() const; 00378 00379 // 00380 // user1 00381 // 00382 public: 00383 /// extract uint2_t from whose lspace() == t_user1 00384 uint2_t u1() const; 00385 private: 00386 void set_u1(uint2_t i); 00387 00388 // 00389 // user2 00390 // 00391 public: 00392 /// extract uint4_t from whose lspace() == t_user2 00393 uint4_t u2() const; 00394 private: 00395 void set_u2(uint4_t i); 00396 00397 // 00398 // user3 00399 // 00400 public: 00401 /// extract uint4_t from whose lspace() == t_user3 00402 uint4_t u3() const; 00403 private: 00404 void set_u3(uint4_t i); 00405 00406 // 00407 // user4 00408 // 00409 public: 00410 /// extract uint4_t from whose lspace() == t_user4 00411 uint4_t u4() const; 00412 private: 00413 void set_u4(uint4_t i); 00414 00415 public: 00416 00417 /**\brief for extent locks only, used by volume manager 00418 * \details 00419 * \anchor FREEEXTLOCK 00420 * Set to true when the extent contains an uncommitted allocated page. 00421 * This is done when a page is allocated in the extent; it is used 00422 * for special handling of extent locks in the lock manager. 00423 * 00424 * The special handling requires a little background: 00425 * 00426 * - extent locks are not in the hierarchy 00427 * - extent IX locks are acquired when a page in the extent is allocated 00428 * (or recovered, in recovery case) 00429 * - extent IX locks are acquired when a page in the extent is freed 00430 * - extent IX locks are acquired when allocating the extent to a store 00431 * - extent EX locks are acquired when deallocating all the extents in 00432 * a store (destroying the store), at which time we have an EX lock on 00433 * the store. 00434 * 00435 * - We need some way to tell when an extent can be freed. It can be 00436 * freed when there are no pages allocated in the extent. 00437 * Presumably we would have any transaction that deallocated a page 00438 * in the extent try to deallocate the extent (i.e., if there are 00439 * no more pages in the extent). But it doesn't acquire an EX lock 00440 * on the extent, so another transaction could slip in and allocate 00441 * pages in the extent. 00442 * - If the transaction (that deleted one or more pages in an extent) 00443 * tries to deallocate the extent at the transaction end, it would 00444 * have to inspect the extent link to tell if the extent has no 00445 * pages in it, and it would still have to do something to avoid races 00446 * with other transactions. 00447 * 00448 * The special handling is this: 00449 * - Transactions that allocate pages in an extent set the bit in the 00450 * \b lock saying there are pages allocated in the extent. 00451 * - Transactions that deallocate pages in an extent clear the bit in the 00452 * \b lock when there are no more pages allocated in the extent. 00453 * - This bypasses a page fix for inspecting the extlink_t. 00454 * - Synchronization for this bit in the lockid is provided by the 00455 * volume manager; the bit is set and cleared only in the volume manager, 00456 * which is a monitor. 00457 * - At transaction end, a transaction that has an IX lock on an 00458 * extent tries to upgrade it to an EX if the extent lock indicates 00459 * that no pages are allocated in the extent. If it succeeds, 00460 * the lock manager can delete the extent while holding the EX lock, 00461 * then free the lock. 00462 * 00463 * When at the end of transaction, lock_m::release_duration() is 00464 * called, the lock manager returns eFOUNDEXTTOFREE when it encounters 00465 * an extent lock with this bit set. 00466 * 00467 */ 00468 void set_ext_has_page_alloc(bool value); 00469 /**\brief for extent locks only, used by lock manager 00470 * \details 00471 * Returns true when the extent contains an uncommitted allocated page. 00472 * See discussion in set_ext_has_page_alloc, above. 00473 */ 00474 bool ext_has_page_alloc() const ; 00475 00476 // construct vacuous lockid_t 00477 NORET lockid_t() ; 00478 /// construct from volume id 00479 NORET lockid_t(const vid_t& vid); 00480 /// construct from full extent id 00481 NORET lockid_t(const extid_t& extid); 00482 /// construct from full store id 00483 NORET lockid_t(const stid_t& stid); 00484 /// construct from full page id 00485 NORET lockid_t(const lpid_t& lpid); 00486 /// construct from full record id 00487 NORET lockid_t(const rid_t& rid); 00488 /// construct from kvl_t (hash of key,value, from vec_t) 00489 NORET lockid_t(const kvl_t& kvl); 00490 /// copy constructor 00491 NORET lockid_t(const lockid_t& i); 00492 /// construct from user1_t 00493 NORET lockid_t(const user1_t& u); 00494 /// construct from user2_t 00495 NORET lockid_t(const user2_t& u); 00496 /// construct from user3_t 00497 NORET lockid_t(const user3_t& u); 00498 /// construct from user4_t 00499 NORET lockid_t(const user4_t& u); 00500 00501 /// extract a full extent id from an extent lock 00502 void extract_extent(extid_t &e) const; 00503 /// extract a full store id from a store, page, or record lock 00504 void extract_stid(stid_t &s) const; 00505 /// extract a full page id from a page or record lock 00506 void extract_lpid(lpid_t &p) const; 00507 /// extract a full record id from a record lock 00508 void extract_rid(rid_t &r) const; 00509 /// extract a kvl_t (hash of key,value) from a key-value lock 00510 void extract_kvl(kvl_t &k) const; 00511 /// extract a user1_t from user-defined entity 1, 2, 3, or 4 00512 void extract_user1(user1_t &u) const; 00513 /// extract a user2_t from user-defined entity 2, 3, or 4 00514 void extract_user2(user2_t &u) const; 00515 /// extract a user3_t from user-defined entity 3 or 4 00516 void extract_user3(user3_t &u) const; 00517 /// extract a user3_t from user-defined entity 4 00518 void extract_user4(user4_t &u) const; 00519 00520 /// Return true if type is t_user1, t_user2, t_user3 or t_user4 00521 bool is_user_lock() const; 00522 00523 /**\brief Nullify all parts of the lockid that apply to children in 00524 * the hierarchy. 00525 * 00526 * If the given space isn't in the hierarchy, this generates a fatal error. 00527 */ 00528 w_rc_t truncate(name_space_t space); 00529 w_rc_t make_parent(); 00530 00531 /// copy operator 00532 lockid_t& operator=(const lockid_t& i); 00533 00534 }; 00535 00536 /** \example lockid_test.cpp*/ 00537 00538 ostream& operator<<(ostream& o, const lockid_t::user1_t& u); 00539 ostream& operator<<(ostream& o, const lockid_t::user2_t& u); 00540 ostream& operator<<(ostream& o, const lockid_t::user3_t& u); 00541 ostream& operator<<(ostream& o, const lockid_t::user4_t& u); 00542 00543 istream& operator>>(istream& o, lockid_t::user1_t& u); 00544 istream& operator>>(istream& o, lockid_t::user2_t& u); 00545 istream& operator>>(istream& o, lockid_t::user3_t& u); 00546 istream& operator>>(istream& o, lockid_t::user4_t& u); 00547 00548 00549 00550 #if W_DEBUG_LEVEL>0 00551 #else 00552 #include "lock_s_inline.h" 00553 #endif 00554 00555 // This is used in probe() for lock cache 00556 inline w_base_t::uint4_t w_hash(const lockid_t& id) 00557 { 00558 return id.hash(); 00559 } 00560 00561 /*<std-footer incl-file-exclusion='LOCK_S_H'> -- do not edit anything below this line -- */ 00562 00563 #endif /*</std-footer>*/