xct.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='XCT_H'>
00025 
00026  $Id: xct.h,v 1.152 2010/07/07 21:43:46 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 XCT_H
00054 #define XCT_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 #if W_DEBUG_LEVEL > 4
00065 // You can rebuild with this turned on 
00066 // if you want comment log records inserted into the log
00067 // to help with deciphering the log when recovery bugs
00068 // are nasty.
00069 #define  X_LOG_COMMENT_ON 1
00070 #define  ADD_LOG_COMMENT_SIG ,const char *debugmsg
00071 #define  ADD_LOG_COMMENT_USE ,debugmsg
00072 #define  LOG_COMMENT_USE(x)  ,x
00073 
00074 #else
00075 
00076 #define  X_LOG_COMMENT_ON 0
00077 #define  ADD_LOG_COMMENT_SIG
00078 #define  ADD_LOG_COMMENT_USE
00079 #define  LOG_COMMENT_USE(x) 
00080 #endif
00081 
00082 class xct_dependent_t;
00083 
00084 /**\cond skip */
00085 /**\internal Tells whether the log is on or off for this xct at this moment.
00086  * \details
00087  * This is used internally for turning on & off the log during 
00088  * top-level actions.
00089  */
00090 class xct_log_t : public smlevel_1 {
00091 private:
00092     //per-thread-per-xct info
00093     bool         _xct_log_off;
00094 public:
00095     NORET        xct_log_t(): _xct_log_off(false) {};
00096     bool         xct_log_is_off() { return _xct_log_off; }
00097     void         set_xct_log_off() { _xct_log_off = true; }
00098     void         set_xct_log_on() { _xct_log_off = false; }
00099 };
00100 /**\endcond skip */
00101 
00102 class lockid_t; // forward
00103 class sdesc_cache_t; // forward
00104 class xct_i; // forward
00105 class restart_m; // forward
00106 class lock_m; // forward
00107 class lock_core_m; // forward
00108 class lock_request_t; // forward
00109 class xct_log_switch_t; // forward
00110 class xct_lock_info_t; // forward
00111 class xct_prepare_alk_log; // forward
00112 class xct_prepare_fi_log; // forward
00113 class xct_prepare_lk_log; // forward
00114 class sm_quark_t; // forward
00115 class smthread_t; // forward
00116 
00117 class logrec_t; // forward
00118 class page_p; // forward
00119 
00120 /**\cond skip
00121  * \brief Class used to keep track of stores to be
00122  * freed or changed from tmp to regular at the end of
00123  * a transaction
00124  */
00125 class stid_list_elem_t  {
00126     public:
00127     stid_t        stid;
00128     w_link_t    _link;
00129 
00130     stid_list_elem_t(const stid_t& theStid)
00131         : stid(theStid)
00132         {};
00133     ~stid_list_elem_t()
00134     {
00135         if (_link.member_of() != NULL)
00136             _link.detach();
00137     }
00138     static w_base_t::uint4_t    link_offset()
00139     {
00140         return W_LIST_ARG(stid_list_elem_t, _link);
00141     }
00142 };
00143 /**\endcond skip */
00144 
00145 
00146 
00147 
00148 /**\brief A transaction. Internal to the storage manager.
00149  * \ingroup LOGSPACE
00150  *
00151  * This class may be used in a limited way for the handling of 
00152  * out-of-log-space conditions.  See \ref LOGSPACE.
00153  */
00154 class xct_t : public smlevel_1 {
00155 /**\cond skip */
00156 #if USE_BLOCK_ALLOC_FOR_LOGREC 
00157     friend class block_alloc<xct_t>;
00158 #endif
00159     friend class xct_i;
00160     friend class smthread_t;
00161     friend class restart_m;
00162     friend class lock_m;
00163     friend class lock_core_m;
00164     friend class lock_request_t;
00165     friend class xct_log_switch_t;
00166     friend class xct_prepare_alk_log;
00167     friend class xct_prepare_fi_log; 
00168     friend class xct_prepare_lk_log; 
00169     friend class sm_quark_t; 
00170 
00171 protected:
00172     enum commit_t { t_normal = 0, t_lazy = 1, t_chain = 2 };
00173 /**\endcond skip */
00174 
00175 /**\cond skip */
00176 public:
00177     typedef xct_state_t           state_t;
00178 
00179     static
00180     xct_t*                        new_xct(
00181         sm_stats_info_t*             stats = 0,  // allocated by caller
00182         timeout_in_ms                timeout = WAIT_SPECIFIED_BY_THREAD);
00183     
00184     static
00185     xct_t*                       new_xct(
00186         const tid_t&                 tid, 
00187         state_t                      s, 
00188         const lsn_t&                 last_lsn,
00189         const lsn_t&                 undo_nxt,
00190         timeout_in_ms                timeout = WAIT_SPECIFIED_BY_THREAD);
00191     static
00192     void                        destroy_xct(xct_t* xd);
00193 
00194 private:
00195     struct xct_core;            // forward  
00196     NORET                        xct_t(
00197         xct_core*                     core,
00198         sm_stats_info_t*             stats,  // allocated by caller
00199         const lsn_t&                 last_lsn,
00200         const lsn_t&                 undo_nxt);
00201     NORET                       ~xct_t();
00202 
00203 public:
00204 
00205     friend ostream&             operator<<(ostream&, const xct_t&);
00206 
00207     static int                  collect(vtable_t&, bool names_too);
00208     void                        vtable_collect(vtable_row_t &);
00209     static void                 vtable_collect_names(vtable_row_t &);
00210 
00211     state_t                     state() const;
00212     void                        set_timeout(timeout_in_ms t) ;
00213 
00214     timeout_in_ms               timeout_c() const;
00215 
00216     /*  
00217      * for 2pc: internal, external
00218      */
00219 public:
00220     void                         force_readonly();
00221     bool                         forced_readonly() const;
00222 
00223     vote_t                       vote() const;
00224     bool                         is_extern2pc() const;
00225     rc_t                         enter2pc(const gtid_t &g);
00226     const gtid_t*                gtid() const;
00227     const server_handle_t&       get_coordinator()const; 
00228     void                         set_coordinator(const server_handle_t &); 
00229     static rc_t                  recover2pc(const gtid_t &g,
00230                                  bool mayblock, xct_t *&);  
00231     static rc_t                  query_prepared(int &numtids);
00232     static rc_t                  query_prepared(int numtids, gtid_t l[]);
00233 
00234     rc_t                         prepare();
00235     rc_t                         log_prepared(bool in_chkpt=false);
00236 
00237     /*
00238      * basic tx commands:
00239      */
00240 public:
00241     static void                 dump(ostream &o); 
00242     static int                  cleanup(bool dispose_prepared=false); 
00243                                  // returns # prepared txs not disposed-of
00244 
00245 
00246     bool                        is_instrumented() {
00247                                    return (__stats != 0);
00248                                 }
00249     void                        give_stats(sm_stats_info_t* s) {
00250                                     w_assert1(__stats == 0);
00251                                     __stats = s;
00252                                 }
00253     void                        clear_stats() {
00254                                     memset(__stats,0, sizeof(*__stats)); 
00255                                 }
00256     sm_stats_info_t*            steal_stats() {
00257                                     sm_stats_info_t*s = __stats; 
00258                                     __stats = 0;
00259                                     return         s;
00260                                 }
00261     const sm_stats_info_t&      const_stats_ref() { return *__stats; }
00262     rc_t                        commit(bool lazy = false, lsn_t* plastlsn=NULL);
00263     rc_t                        rollback(const lsn_t &save_pt);
00264     rc_t                        save_point(lsn_t& lsn);
00265     rc_t                        chain(bool lazy = false);
00266     rc_t                        abort(bool save_stats = false);
00267 
00268     // used by restart.cpp, some logrecs
00269 protected:
00270     sm_stats_info_t&            stats_ref() { return *__stats; }
00271     rc_t                        dispose();
00272     void                        change_state(state_t new_state);
00273     void                        set_first_lsn(const lsn_t &) ;
00274     void                        set_last_lsn(const lsn_t &) ;
00275     void                        set_undo_nxt(const lsn_t &) ;
00276     void                        prepare_restore_log_resv(int, int, int, int);
00277 /**\endcond skip */
00278 
00279 public:
00280 
00281     // used by checkpoint, restart:
00282     const lsn_t&                last_lsn() const;
00283     const lsn_t&                first_lsn() const;
00284     const lsn_t&                undo_nxt() const;
00285     const logrec_t*             last_log() const;
00286     fileoff_t                   get_log_space_used() const;
00287     rc_t                        wait_for_log_space(fileoff_t amt);
00288     
00289     // used by restart, chkpt among others
00290     static xct_t*               look_up(const tid_t& tid);
00291     static tid_t                oldest_tid();        // with min tid value
00292     static tid_t                youngest_tid();        // with max tid value
00293 /**\cond skip */
00294     static void                 update_youngest_tid(const tid_t &);
00295 /**\endcond skip */
00296 
00297     // used by sm.cpp:
00298     static w_base_t::uint4_t    num_active_xcts();
00299 
00300 /**\cond skip */
00301     // used for compensating (top-level actions)
00302     const lsn_t&                anchor(bool grabit = true);
00303     void                        release_anchor(bool compensate
00304                                    ADD_LOG_COMMENT_SIG
00305                                    );
00306     int                         compensated_op_depth() const ;
00307 
00308     // -------------------------------------------------------------
00309     // start_crit and stop_crit are used by the io_m to
00310     // ensure that at most one thread of the attached transaction
00311     // enters the io_m at a time. That was the original idea; now it's
00312     // making sure that at most one thread that's in an sm update operation
00313     // enters the io_m at any time (allowing concurrent read-only activity). 
00314     //
00315     // start_crit grabs the xct's 1thread_log mutex if it doesn't
00316     // already hold it.  False means we don't actually grab the
00317     // anchor, so it's not really starting a top-level action.
00318 
00319     void                        start_crit() { (void) anchor(false); }
00320     // stop_crit frees the xct's 1thread_log mutex if the depth of
00321     // anchor()/release() calls reaches 0.
00322     // False means we don't compensate, 
00323     // so it's not really finishing a top-level action.
00324 
00325     void                        stop_crit() {(void) release_anchor(false
00326                                             LOG_COMMENT_USE( "stopcrit"));}
00327     // -------------------------------------------------------------
00328     
00329     void                        compensate(const lsn_t&, 
00330                                           bool undoable
00331                                           ADD_LOG_COMMENT_SIG
00332                                           );
00333     // for recovery:
00334     void                        compensate_undo(const lsn_t&);
00335 /**\endcond skip */
00336 
00337     // For handling log-space warnings
00338     // If you've warned wrt a tx once, and the server doesn't
00339     // choose to abort that victim, you don't want every
00340     // ssm prologue to warn thereafter. This allows the
00341     // callback function to turn off the warnings for the (non-)victim. 
00342     void                         log_warn_disable();
00343     void                         log_warn_resume();
00344     bool                         log_warn_is_on() const;
00345 
00346 /**\cond skip */
00347 
00348 public:
00349     // used in sm.cpp
00350     rc_t                        add_dependent(xct_dependent_t* dependent);
00351     rc_t                        remove_dependent(xct_dependent_t* dependent);
00352     bool                        find_dependent(xct_dependent_t* dependent);
00353 
00354     //
00355     //        logging functions -- used in logstub_gen.cpp only
00356     //
00357     bool                        is_log_on() const;
00358     rc_t                        get_logbuf(logrec_t*&, const page_p *p = 0);
00359     rc_t                        give_logbuf(logrec_t*, const page_p *p = 0);
00360 
00361     //
00362     //        Used by I/O layer
00363     //
00364     void                        AddStoreToFree(const stid_t& stid);
00365     void                        AddLoadStore(const stid_t& stid);
00366     //        Used by vol.cpp
00367     void                        set_alloced() { }
00368 
00369     void                        num_extents_marked_for_deletion(
00370                                         base_stat_t &num);
00371 public:
00372     //        For SM interface:
00373     void                        GetEscalationThresholds(
00374                                         w_base_t::int4_t &toPage, 
00375                                         w_base_t::int4_t &toStore, 
00376                                         w_base_t::int4_t &toVolume);
00377     void                        SetEscalationThresholds(
00378                                         w_base_t::int4_t toPage,
00379                                         w_base_t::int4_t toStore, 
00380                                         w_base_t::int4_t toVolume);
00381     bool                        set_lock_cache_enable(bool enable);
00382     bool                        lock_cache_enabled();
00383 
00384 protected:
00385     /////////////////////////////////////////////////////////////////
00386     // the following is put here because smthread 
00387     // doesn't know about the structures
00388     // and we have changed these to be a per-thread structures.
00389     static lockid_t*            new_lock_hierarchy();
00390     static sdesc_cache_t*       new_sdesc_cache_t();
00391     static xct_log_t*           new_xct_log_t();
00392     void                        steal(lockid_t*&, sdesc_cache_t*&, xct_log_t*&);
00393     void                        stash(lockid_t*&, sdesc_cache_t*&, xct_log_t*&);
00394 
00395     void                        attach_thread(); 
00396     void                        detach_thread(); 
00397 
00398 
00399     // stored per-thread, used by lock.cpp
00400     lockid_t*                   lock_info_hierarchy() const {
00401                                     return me()->lock_hierarchy();
00402                                 }
00403 public:
00404     // stored per-thread or per-xct, used by dir.cpp
00405     sdesc_cache_t*              sdesc_cache() const;
00406 
00407 protected:
00408     // for xct_log_switch_t:
00409     /// Set {thread,xct} pair's log-state to on/off (s) and return the old value.
00410     switch_t                    set_log_state(switch_t s);
00411     /// Restore {thread,xct} pair's log-state to on/off (s) 
00412     void                        restore_log_state(switch_t s);
00413 
00414 
00415 public:
00416     concurrency_t                get_lock_level(); // non-const: acquires mutex 
00417     void                         lock_level(concurrency_t l);
00418 
00419     int                          num_threads();          
00420     rc_t                         check_one_thread_attached() const;   
00421     void                         attach_update_thread();
00422     void                         detach_update_thread();
00423     int                          update_threads() const;
00424 
00425 protected:
00426     // For use by lock manager:
00427     w_rc_t                       lockblock(timeout_in_ms timeout);// await other thread
00428     void                         lockunblock(); // inform other waiters
00429     const w_base_t::int4_t*      GetEscalationThresholdsArray();
00430 
00431     rc_t                         check_lock_totals(int nex, 
00432                                         int nix, int nsix, int ) const;
00433     rc_t                         obtain_locks(lock_mode_t mode, 
00434                                         int nlks, const lockid_t *l); 
00435     rc_t                         obtain_one_lock(lock_mode_t mode, 
00436                                         const lockid_t &l); 
00437 
00438     xct_lock_info_t*             lock_info() const;
00439 
00440 public:
00441     // XXX this is only for chkpt::take().  This problem needs to
00442     // be fixed correctly.  DO NOT USE THIS.  Really want a
00443     // friend that is just a friend on some methods, not the entire class.
00444     static w_rc_t                acquire_xlist_mutex();
00445     static void                  release_xlist_mutex();
00446     static void                  assert_xlist_mutex_not_mine();
00447     static void                  assert_xlist_mutex_is_mine();
00448     static bool                  xlist_mutex_is_mine();
00449 
00450     /* "poisons" the transaction so cannot block on locks (or remain
00451        blocked if already so), instead aborting the offending lock
00452        request with eDEADLOCK. We use eDEADLOCK instead of
00453        eLOCKTIMEOUT because all transactions must expect the former
00454        and must abort in response; transactions which specified
00455        WAIT_FOREVER won't be expecting timeouts, and the SM uses
00456        timeouts (WAIT_IMMEDIATE) as internal signals which do not
00457        usually trigger a transaction abort.
00458 
00459        chkpt::take uses this to ensure timely and deadlock-free
00460        completion/termination of transactions which would prevent a
00461        checkpoint from freeing up needed log space.
00462      */
00463     void                         force_nonblocking();
00464 
00465 
00466 /////////////////////////////////////////////////////////////////
00467 // DATA
00468 /////////////////////////////////////////////////////////////////
00469 protected:
00470     // list of all transactions instances
00471     w_link_t                      _xlink;
00472     static w_descend_list_t<xct_t, queue_based_lock_t, tid_t> _xlist;
00473     void                         put_in_order();
00474 private:
00475     static queue_based_lock_t    _xlist_mutex;
00476 
00477     sm_stats_info_t*             __stats; // allocated by user
00478     lockid_t*                    __saved_lockid_t;
00479     sdesc_cache_t*                __saved_sdesc_cache_t;
00480     xct_log_t*                   __saved_xct_log_t;
00481 
00482     static tid_t                 _nxt_tid;// only safe for pre-emptive 
00483                                         // threads on 64-bit platforms
00484     static tid_t                 _oldest_tid;
00485     
00486     // NB: must replicate because _xlist keys off it...
00487     // NB: can't be const because we might chain...
00488     tid_t                        _tid;
00489 
00490 public:
00491     void                         acquire_1thread_xct_mutex() const; // serialize
00492     void                         release_1thread_xct_mutex() const; // concurrency ok
00493     bool                         is_1thread_log_mutex_mine() const; 
00494 /**\endcond skip */
00495 
00496 private:
00497     void                         acquire_1thread_log_mutex();
00498     void                         release_1thread_log_mutex();
00499     void                         assert_1thread_log_mutex_free()const;
00500 private:
00501     bool                         is_1thread_xct_mutex_mine() const;
00502     void                         assert_1thread_xct_mutex_free()const;
00503 
00504     rc_t                         _abort();
00505     rc_t                         _commit(w_base_t::uint4_t flags,
00506                                                  lsn_t* plastlsn=NULL);
00507 
00508 protected:
00509     // for xct_log_switch_t:
00510     switch_t                    set_log_state(switch_t s, bool &nested);
00511     void                        restore_log_state(switch_t s, bool nested);
00512 
00513 private:
00514     bool                        one_thread_attached() const;   // assertion
00515     // helper function for compensate() and compensate_undo()
00516     void                        _compensate(const lsn_t&, bool undoable = false);
00517 
00518     w_base_t::int4_t            escalationThresholds[lockid_t::NUMLEVELS-1];
00519 public:
00520     void                        SetDefaultEscalationThresholds();
00521 
00522     void                        ClearAllStoresToFree();
00523     void                        FreeAllStoresToFree();
00524     rc_t                        PrepareLogAllStoresToFree();
00525     void                        DumpStoresToFree();
00526     rc_t                        ConvertAllLoadStoresToRegularStores();
00527     void                        ClearAllLoadStores();
00528 
00529     ostream &                   dump_locks(ostream &) const;
00530 
00531     /////////////////////////////////////////////////////////////////
00532 private:
00533     /////////////////////////////////////////////////////////////////
00534     // non-const because it acquires mutex:
00535     // removed, now that the lock mgrs use the const,INLINE-d form
00536     // timeout_in_ms        timeout(); 
00537 
00538     static void                 xct_stats(
00539                                     u_long&             begins,
00540                                     u_long&             commits,
00541                                     u_long&             aborts,
00542                                     bool                 reset);
00543 
00544     w_rc_t                     _flush_logbuf();
00545     w_rc_t                     _sync_logbuf(bool block=true);
00546     void                       _teardown(bool is_chaining);
00547 
00548 private:
00549     /* A nearly-POD struct whose only job is to enable a N:1
00550        relationship between the log streams of a transaction (xct_t)
00551        and its core functionality such as locking and 2PC (xct_core).
00552 
00553        Any transaction state which should not eventually be replicated
00554        per-thread goes here. Usually such state is protected by the
00555        1-thread-xct-mutex.
00556 
00557        Static data members can stay in xct_t, since they're not even
00558        duplicated per-xct, let alone per-thread.
00559      */
00560     struct xct_core
00561     {
00562         xct_core(tid_t const &t, state_t s, timeout_in_ms timeout);
00563         ~xct_core();
00564 
00565         //-- from xct.h ----------------------------------------------------
00566         tid_t                  _tid;
00567         timeout_in_ms          _timeout; // default timeout value for lock reqs
00568         bool                   _warn_on;
00569         xct_lock_info_t*       _lock_info;
00570 
00571         /* 
00572          * _lock_cache_enable is protected by its own mutex, because
00573          * it is used from the lock manager, and the lock mgr is used
00574          * by the volume mgr, which necessarily holds the xct's 1thread_log
00575          * mutex.  Thus, in order to avoid mutex-mutex deadlocks,
00576          * we have a mutex to cover _lock_cache_enable that is used
00577          * for NOTHING but reading and writing this datum.
00578          */
00579         bool                   _lock_cache_enable;
00580         
00581         // the 1thread_xct mutex is used to ensure that only one thread
00582         // is using the xct structure on behalf of a transaction 
00583         // TBD whether this should be a spin- or block- lock:
00584         queue_based_lock_t     _1thread_xct;
00585         
00586         // Count of number of threads are doing update operations.
00587         // Used by start_crit and stop_crit.
00588         volatile int           _updating_operations; 
00589 
00590         // to be manipulated only by smthread funcs
00591         volatile int           _threads_attached; 
00592 
00593         // used in lockblock, lockunblock, by lock_core 
00594         pthread_cond_t            _waiters_cond;  // paired with _waiters_mutex
00595         mutable pthread_mutex_t   _waiters_mutex;  // paired with _waiters_cond
00596 
00597         state_t                   _state;
00598         bool                      _forced_readonly;
00599         vote_t                    _vote;
00600         gtid_t *                  _global_tid; // null if not participating
00601         server_handle_t*          _coord_handle; // ignored for now
00602         bool                      _read_only;
00603 
00604         /*
00605          * List of stores which this xct will free after completion
00606          * Protected by _1thread_xct.
00607          */
00608         w_list_t<stid_list_elem_t,queue_based_lock_t>    _storesToFree;
00609 
00610         /*
00611          * List of load stores:  converted to regular on xct commit,
00612          *                act as a temp files during xct
00613          */
00614         w_list_t<stid_list_elem_t,queue_based_lock_t>    _loadStores;
00615 
00616         volatile int      _xct_ended; // used for self-checking (assertions) only
00617     };
00618     
00619 private: // all data members private
00620     // the 1thread_xct mutex is used to ensure that only one thread
00621     // is using the xct structure on behalf of a transaction 
00622     // It protects a number of things, including the xct_dependents list
00623 
00624     // the 1thread_log mutex is used to ensure that only one thread
00625     // is logging on behalf of this xct 
00626     mutable queue_based_lock_t   _1thread_log;
00627 
00628     lsn_t                        _first_lsn;
00629     lsn_t                        _last_lsn;
00630     lsn_t                        _undo_nxt;
00631 
00632     // list of dependents: protected by _1thread_xct
00633     // FRJ: this will become per-stream and not need the mutex any more
00634     w_list_t<xct_dependent_t,queue_based_lock_t>    _dependent_list;
00635 
00636     /*
00637      *  lock request stuff
00638      */
00639     static lockid_t::name_space_t    convert(concurrency_t cc);
00640     static concurrency_t             convert(lockid_t::name_space_t n);
00641 
00642     /*
00643      *  log_m related
00644      */
00645     logrec_t*                    _last_log;    // last log generated by xct
00646     logrec_t*                    _log_buf;
00647 
00648     /* track log space needed to avoid wedging the transaction in the
00649        event of an abort due to full log
00650      */ 
00651     fileoff_t                    _log_bytes_rsvd; // reserved for rollback
00652     fileoff_t                    _log_bytes_ready; // avail for insert/reserv
00653     fileoff_t                    _log_bytes_used; // total used by the xct
00654     fileoff_t                    _log_bytes_reserved_space;//requested from
00655                                  // log -- used ONLY for assertions/debugging
00656     bool                         _rolling_back;// true if aborting OR
00657                                  // in rollback_work (which does not change
00658                                  // the xct state).
00659 
00660 #if CHECK_NESTING_VARIABLES
00661     // for assertions only
00662     volatile int                 _acquire_1thread_log_depth;  
00663 public:
00664     void inc_acquire_1thread_log_depth() { _acquire_1thread_log_depth ++; }
00665     void dec_acquire_1thread_log_depth() { -- _acquire_1thread_log_depth; }
00666     int  acquire_1thread_log_depth() const { return 
00667                                                _acquire_1thread_log_depth; }
00668 #else
00669 public:
00670     void inc_acquire_1thread_log_depth() { }
00671     void dec_acquire_1thread_log_depth() { }
00672     int  acquire_1thread_log_depth() const { return  0; }
00673 #endif
00674 private:
00675 
00676      volatile int                _in_compensated_op; 
00677         // in the midst of a compensated operation
00678         // use an int because they can be nested.
00679      lsn_t                       _anchor;
00680         // the anchor for the outermost compensated op
00681 
00682      xct_core*                   _core;
00683 
00684 public:
00685     tid_t                       tid() const { 
00686                                     w_assert1(_tid == _core->_tid);
00687                                     return _tid; }
00688 };
00689 
00690 /**\cond skip */
00691 class auto_release_anchor_t {
00692 private:
00693     xct_t* _xd;
00694     lsn_t _anchor;
00695     bool _and_compensate;
00696     int    _line; // for debugging
00697 
00698     operator lsn_t const&() const { return _anchor; }
00699 public:
00700 
00701     auto_release_anchor_t(bool and_compensate, int line)
00702         : _xd(xct()), _and_compensate(and_compensate), _line(line)
00703     {
00704     if(_xd)
00705         _anchor = _xd->anchor(_and_compensate);
00706     }
00707     void compensate() {
00708     if(_xd)
00709         _xd->compensate(_anchor, false
00710                 LOG_COMMENT_USE("auto_release_anchor_t")
00711                 );
00712     _xd = 0; // cancel pending release in destructor
00713     }
00714     ~auto_release_anchor_t(); // in xct.cpp
00715 };
00716 /**\endcond skip */
00717 
00718 /*
00719  * Use X_DO inside compensated operations
00720  */
00721 #if X_LOG_COMMENT_ON
00722 #define X_DO1(x,anchor,line)             \
00723 {                           \
00724     w_rc_t __e = (x);       \
00725     if (__e.is_error()) {        \
00726         w_assert3(xct());        \
00727         W_COERCE(xct()->rollback(anchor));        \
00728         xct()->release_anchor(true, line );    \
00729         return RC_AUGMENT(__e); \
00730     } \
00731 }
00732 #define to_string(x) # x
00733 #define X_DO(x,anchor) X_DO1(x,anchor, to_string(x))
00734 
00735 #else
00736 
00737 #define X_DO(x,anchor)             \
00738 {                           \
00739     w_rc_t __e = (x);       \
00740     if (__e.is_error()) {        \
00741         w_assert3(xct());        \
00742         W_COERCE(xct()->rollback(anchor));        \
00743         xct()->release_anchor(true);        \
00744         return RC_AUGMENT(__e); \
00745     } \
00746 }
00747 #endif
00748 
00749 /**\cond skip */
00750 class xct_log_switch_t : public smlevel_0 {
00751     /*
00752      * NB: use sparingly!!!! EVERYTHING DONE UNDER
00753      * CONTROL OF ONE OF THESE IS A CRITICAL SECTION
00754      * This is necessary to support multi-threaded xcts,
00755      * to prevent one thread from turning off the log
00756      * while another needs it on, or vice versa.
00757      */
00758     switch_t old_state;
00759 public:
00760     /// Initialize old state
00761     NORET xct_log_switch_t(switch_t s)  : old_state(OFF)
00762     {
00763         if(smlevel_1::log) {
00764             INC_TSTAT(log_switches);
00765             if (xct()) {
00766                 old_state = xct()->set_log_state(s);
00767             }
00768         }
00769     }
00770 
00771     NORET
00772     ~xct_log_switch_t()  {
00773         if(smlevel_1::log) {
00774             if (xct()) {
00775                 xct()->restore_log_state(old_state);
00776             }
00777         }
00778     }
00779 };
00780 
00781 inline
00782 bool xct_t::is_log_on() const {
00783     return (me()->xct_log()->xct_log_is_off() == false);
00784 }
00785 /**\endcond skip */
00786 
00787 /* XXXX This is somewhat hacky becuase I am working on cleaning
00788    up the xct_i xct iterator to provide various levels of consistency.
00789    Until then, the "locking option" provides enough variance so
00790    code need not be duplicated or have deep call graphs. */
00791 
00792 /**\brief Iterator over transaction list.
00793  *
00794  * This is exposed for the purpose of coping with out-of-log-space 
00795  * conditions. See \ref LOGSPACE.
00796  */
00797 class xct_i  {
00798 public:
00799     // NB: still not safe, since this does not
00800     // lock down the list for the entire iteration.
00801     
00802     // FRJ: Making it safe -- all non-debug users lock it down
00803     // manually right now anyway; the rest *should* to avoid bugs.
00804 
00805     /// True if this thread holds the transaction list mutex.
00806     bool locked_by_me() const {
00807         if(xct_t::xlist_mutex_is_mine()) {
00808             W_IFDEBUG1(if(_may_check) w_assert1(_locked);)
00809             return true;
00810         }
00811         return false;
00812     }
00813 
00814     /// Release transaction list mutex if this thread holds it.
00815     void never_mind() {
00816         // Be careful here: must leave in the
00817         // state it was when we constructed this.
00818         if(_locked && locked_by_me()) {
00819             *(const_cast<bool *>(&_locked)) = false; // grot
00820             xct_t::release_xlist_mutex();
00821         }
00822     }
00823     /// Get transaction at cursor.
00824     xct_t* curr() const { return unsafe_iterator.curr(); }
00825     /// Advance cursor.
00826     xct_t* next() { return unsafe_iterator.next(); }
00827 
00828     /**\cond skip */
00829     // Note that this is called to INIT the attribute "locked"
00830     static bool init_locked(bool lockit) 
00831     {
00832         if(lockit) {
00833             W_COERCE(xct_t::acquire_xlist_mutex());
00834         }
00835         return lockit;
00836     }
00837     /**\endcond skip */
00838 
00839     /**\brief Constructor.
00840     *
00841     * @param[in] locked_accesses Set to true if you want this
00842     * iterator to be safe, false if you don't care or if you already
00843     * hold the transaction-list mutex.
00844     */
00845     NORET xct_i(bool locked_accesses)
00846         : _locked(init_locked(locked_accesses)),
00847         _may_check(locked_accesses),
00848         unsafe_iterator(xct_t::_xlist)
00849     {
00850         w_assert1(_locked == locked_accesses);
00851         _check(_locked);
00852     }
00853 
00854     /// Desctructor. Calls never_mind() if necessary.
00855     NORET ~xct_i() { 
00856         if(locked_by_me()) {
00857           _check(true);
00858           never_mind(); 
00859           _check(false);
00860         }
00861     }
00862 
00863 private:
00864     void _check(bool b) const  {
00865           if(!_may_check) return;
00866           if(b) xct_t::assert_xlist_mutex_is_mine(); 
00867           else  xct_t::assert_xlist_mutex_not_mine(); 
00868     }
00869     // FRJ: make sure init_locked runs before we actually create the iterator
00870     const bool            _locked;
00871     const bool            _may_check;
00872     w_list_i<xct_t,queue_based_lock_t> unsafe_iterator;
00873 
00874     // disabled
00875     xct_i(const xct_i&);
00876     xct_i& operator=(const xct_i&);
00877 };
00878     
00879 
00880 /**\cond skip */
00881 // For use in sm functions that don't allow
00882 // active xct when entered.  These are functions that
00883 // apply to local volumes only.
00884 class xct_auto_abort_t : public smlevel_1 {
00885 public:
00886     xct_auto_abort_t() : _xct(xct_t::new_xct()) {}
00887     ~xct_auto_abort_t() {
00888         switch(_xct->state()) {
00889         case smlevel_1::xct_ended:
00890             // do nothing
00891             break;
00892         case smlevel_1::xct_active:
00893             W_COERCE(_xct->abort());
00894             break;
00895         default:
00896             W_FATAL(eINTERNAL);
00897         }
00898         xct_t::destroy_xct(_xct);
00899     }
00900     rc_t commit() {
00901         // These are only for local txs
00902         // W_DO(_xct->prepare());
00903         W_DO(_xct->commit());
00904         return RCOK;
00905     }
00906     rc_t abort() {W_DO(_xct->abort()); return RCOK;}
00907 
00908 private:
00909     xct_t*        _xct;
00910 };
00911 
00912 inline
00913 xct_t::state_t
00914 xct_t::state() const
00915 {
00916     return _core->_state;
00917 }
00918 
00919 
00920 inline
00921 bool
00922 operator>(const xct_t& x1, const xct_t& x2)
00923 {
00924     return (x1.tid() > x2.tid());
00925 }
00926 
00927 inline void
00928 xct_t::SetEscalationThresholds(w_base_t::int4_t toPage, 
00929                 w_base_t::int4_t toStore, 
00930                 w_base_t::int4_t toVolume)
00931 {
00932     if (toPage != dontModifyThreshold)
00933                 escalationThresholds[2] = toPage;
00934     
00935     if (toStore != dontModifyThreshold)
00936                 escalationThresholds[1] = toStore;
00937     
00938     if (toVolume != dontModifyThreshold)
00939                 escalationThresholds[0] = toVolume;
00940 }
00941 
00942 inline void
00943 xct_t::SetDefaultEscalationThresholds()
00944 {
00945     SetEscalationThresholds(smlevel_0::defaultLockEscalateToPageThreshold,
00946             smlevel_0::defaultLockEscalateToStoreThreshold,
00947             smlevel_0::defaultLockEscalateToVolumeThreshold);
00948 }
00949 
00950 inline void
00951 xct_t::GetEscalationThresholds(w_base_t::int4_t &toPage, 
00952                 w_base_t::int4_t &toStore, 
00953                 w_base_t::int4_t &toVolume)
00954 {
00955     toPage = escalationThresholds[2];
00956     toStore = escalationThresholds[1];
00957     toVolume = escalationThresholds[0];
00958 }
00959 
00960 inline const w_base_t::int4_t *
00961 xct_t::GetEscalationThresholdsArray()
00962 {
00963     return escalationThresholds;
00964 }
00965 
00966 inline
00967 xct_t::vote_t
00968 xct_t::vote() const
00969 {
00970     return _core->_vote;
00971 }
00972 
00973 inline
00974 const lsn_t&
00975 xct_t::last_lsn() const
00976 {
00977     return _last_lsn;
00978 }
00979 
00980 inline
00981 void
00982 xct_t::set_last_lsn( const lsn_t&l)
00983 {
00984     _last_lsn = l;
00985 }
00986 
00987 inline
00988 const lsn_t&
00989 xct_t::first_lsn() const
00990 {
00991     return _first_lsn;
00992 }
00993 
00994 inline
00995 void
00996 xct_t::set_first_lsn(const lsn_t &l) 
00997 {
00998     _first_lsn = l;
00999 }
01000 
01001 inline
01002 const lsn_t&
01003 xct_t::undo_nxt() const
01004 {
01005     return _undo_nxt;
01006 }
01007 
01008 inline
01009 void
01010 xct_t::set_undo_nxt(const lsn_t &l) 
01011 {
01012     _undo_nxt = l;
01013 }
01014 
01015 inline
01016 const logrec_t*
01017 xct_t::last_log() const
01018 {
01019     return _last_log;
01020 }
01021 
01022 inline
01023 bool
01024 xct_t::forced_readonly() const
01025 {
01026     return _core->_forced_readonly;
01027 }
01028 
01029 /*********************************************************************
01030  *
01031  *  bool xct_t::is_extern2pc()
01032  *
01033  *  return true iff this tx is participating
01034  *  in an external 2-phase commit protocol, 
01035  *  which is effected by calling enter2pc() on this
01036  *
01037  *********************************************************************/
01038 inline bool            
01039 xct_t::is_extern2pc() 
01040 const
01041 {
01042     // true if is a thread of global tx
01043     return _core->_global_tid != 0;
01044 }
01045 
01046 
01047 inline
01048 const gtid_t*           
01049 xct_t::gtid() const 
01050 {
01051     return _core->_global_tid;
01052 }
01053 
01054 /**\endcond skip */
01055 
01056 /*<std-footer incl-file-exclusion='XCT_H'>  -- do not edit anything below this line -- */
01057 
01058 #endif          /*</std-footer>*/

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