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

Generated on Mon Jan 2 15:13:57 2012 for Shore Storage Manager by  doxygen 1.4.7