lock_s.h

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>*/

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7