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

Generated on Mon Nov 8 11:12:38 2010 for Shore Storage Manager by  doxygen 1.4.7