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.161 2010/12/08 17:37:43 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  X_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  X_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 (used to grab) the xct's 1thread_log mutex if it doesn't
00327     // already hold it.  
00328     //
00329     // NOTE: we might be safe to skip this now that we only allow
00330     // one update thread to be in the sm at any one time, cutting the
00331     // others off at the point of entering the sm, rather than 
00332     // making them wait for the 1thread mutex.  We made this change
00333     // so that we could use savepoints for partial rollback to handle
00334     // errors at levels above (as well as below) the sm_io level.
00335     // See AUTO_ROLLBACK_work, auto_rollback_t , here
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                                     return 
00511                                         me()->is_update_thread()
00512                                         ||
00513                                         smlevel_0::in_recovery()
00514                                         ;
00515     }
00516 /**\endcond skip */
00517 
00518 private:
00519     void                         acquire_1thread_log_mutex() {
00520         // This is a sanity check: we want to 
00521         // remove the 1thread log mutex altogether; given that,
00522         // we assert that there is one and only one update thread
00523         // and that thread is us.
00524         w_assert0(me()->is_update_thread() || smlevel_0::in_recovery());
00525     }
00526     void                         release_1thread_log_mutex() {
00527         // This is a sanity check: we want to 
00528         // remove the 1thread log mutex altogether; given that,
00529         // we assert that there is one and only one update thread
00530         // and that thread is us.
00531         w_assert0(me()->is_update_thread() || smlevel_0::in_recovery());
00532     }
00533 private:
00534     bool                         is_1thread_xct_mutex_mine() const;
00535     void                         assert_1thread_xct_mutex_free()const;
00536 
00537     rc_t                         _abort();
00538     rc_t                         _commit(w_base_t::uint4_t flags,
00539                                                  lsn_t* plastlsn=NULL);
00540 
00541 protected:
00542     // for xct_log_switch_t:
00543     switch_t                    set_log_state(switch_t s, bool &nested);
00544     void                        restore_log_state(switch_t s, bool nested);
00545 
00546 private:
00547     bool                        one_thread_attached() const;   // assertion
00548     // helper function for compensate() and compensate_undo()
00549     void                        _compensate(const lsn_t&, bool undoable = false);
00550 
00551     w_base_t::int4_t            escalationThresholds[lockid_t::NUMLEVELS-1];
00552 public:
00553     void                        SetDefaultEscalationThresholds();
00554 
00555     void                        ClearAllStoresToFree();
00556     void                        FreeAllStoresToFree();
00557     rc_t                        PrepareLogAllStoresToFree();
00558     void                        DumpStoresToFree();
00559     rc_t                        ConvertAllLoadStoresToRegularStores();
00560     void                        ClearAllLoadStores();
00561 
00562     ostream &                   dump_locks(ostream &) const;
00563 
00564     /////////////////////////////////////////////////////////////////
00565 private:
00566     /////////////////////////////////////////////////////////////////
00567     // non-const because it acquires mutex:
00568     // removed, now that the lock mgrs use the const,INLINE-d form
00569     // timeout_in_ms        timeout(); 
00570 
00571     static void                 xct_stats(
00572                                     u_long&             begins,
00573                                     u_long&             commits,
00574                                     u_long&             aborts,
00575                                     bool                 reset);
00576 
00577     w_rc_t                     _flush_logbuf();
00578     w_rc_t                     _sync_logbuf(bool block=true);
00579     void                       _teardown(bool is_chaining);
00580 
00581 #if defined(USE_BLOCK_ALLOC_FOR_XCT_IMPL) && (USE_BLOCK_ALLOC_FOR_XCT_IMPL==1)
00582 public:
00583 #else
00584 private:
00585 #endif
00586     /* A nearly-POD struct whose only job is to enable a N:1
00587        relationship between the log streams of a transaction (xct_t)
00588        and its core functionality such as locking and 2PC (xct_core).
00589 
00590        Any transaction state which should not eventually be replicated
00591        per-thread goes here. Usually such state is protected by the
00592        1-thread-xct-mutex.
00593 
00594        Static data members can stay in xct_t, since they're not even
00595        duplicated per-xct, let alone per-thread.
00596      */
00597     struct xct_core
00598     {
00599         xct_core(tid_t const &t, state_t s, timeout_in_ms timeout);
00600         ~xct_core();
00601 
00602         //-- from xct.h ----------------------------------------------------
00603         tid_t                  _tid;
00604         timeout_in_ms          _timeout; // default timeout value for lock reqs
00605         bool                   _warn_on;
00606         xct_lock_info_t*       _lock_info;
00607 
00608         /* 
00609          * _lock_cache_enable is protected by its own mutex, because
00610          * it is used from the lock manager, and the lock mgr is used
00611          * by the volume mgr, which necessarily holds the xct's 1thread_log
00612          * mutex.  Thus, in order to avoid mutex-mutex deadlocks,
00613          * we have a mutex to cover _lock_cache_enable that is used
00614          * for NOTHING but reading and writing this datum.
00615          */
00616         bool                   _lock_cache_enable;
00617         
00618         // the 1thread_xct mutex is used to ensure that only one thread
00619         // is using the xct structure on behalf of a transaction 
00620         // TBD whether this should be a spin- or block- lock:
00621         queue_based_lock_t     _1thread_xct;
00622         
00623         // Count of number of threads are doing update operations.
00624         // Used by start_crit and stop_crit.
00625         volatile int           _updating_operations; 
00626 
00627         // to be manipulated only by smthread funcs
00628         volatile int           _threads_attached; 
00629 
00630         // used in lockblock, lockunblock, by lock_core 
00631         pthread_cond_t            _waiters_cond;  // paired with _waiters_mutex
00632         mutable pthread_mutex_t   _waiters_mutex;  // paired with _waiters_cond
00633 
00634         state_t                   _state;
00635         bool                      _forced_readonly;
00636         vote_t                    _vote;
00637         gtid_t *                  _global_tid; // null if not participating
00638         server_handle_t*          _coord_handle; // ignored for now
00639         bool                      _read_only;
00640 
00641         /*
00642          * List of stores which this xct will free after completion
00643          * Protected by _1thread_xct.
00644          */
00645         w_list_t<stid_list_elem_t,queue_based_lock_t>    _storesToFree;
00646 
00647         /*
00648          * List of load stores:  converted to regular on xct commit,
00649          *                act as a temp files during xct
00650          */
00651         w_list_t<stid_list_elem_t,queue_based_lock_t>    _loadStores;
00652 
00653         volatile int      _xct_ended; // used for self-checking (assertions) only
00654         bool              _xct_aborting; // distinguish abort()ing xct from
00655         // commit()ing xct when they are in state xct_freeing_space
00656     };
00657     
00658 private: // all data members private
00659     // the 1thread_xct mutex is used to ensure that only one thread
00660     // is using the xct structure on behalf of a transaction 
00661     // It protects a number of things, including the xct_dependents list
00662 
00663     // the 1thread_log mutex is used to ensure that only one thread
00664     // is logging on behalf of this xct 
00665     mutable queue_based_lock_t   _1thread_log;
00666 
00667     lsn_t                        _first_lsn;
00668     lsn_t                        _last_lsn;
00669     lsn_t                        _undo_nxt;
00670 
00671     // list of dependents: protected by _1thread_xct
00672     // FRJ: this will become per-stream and not need the mutex any more
00673     w_list_t<xct_dependent_t,queue_based_lock_t>    _dependent_list;
00674 
00675     /*
00676      *  lock request stuff
00677      */
00678     static lockid_t::name_space_t    convert(concurrency_t cc);
00679     static concurrency_t             convert(lockid_t::name_space_t n);
00680 
00681     /*
00682      *  log_m related
00683      */
00684     logrec_t*                    _last_log;    // last log generated by xct
00685     logrec_t*                    _log_buf;
00686 
00687     /* track log space needed to avoid wedging the transaction in the
00688        event of an abort due to full log
00689      */ 
00690     fileoff_t                    _log_bytes_rsvd; // reserved for rollback
00691     fileoff_t                    _log_bytes_ready; // avail for insert/reserv
00692     fileoff_t                    _log_bytes_used; // total used by the xct
00693     fileoff_t                    _log_bytes_used_fwd; // used by the xct in
00694                                  // forward activity (including partial
00695                                  // rollbacks) -- ONLY for assertions/debugging
00696     fileoff_t                    _log_bytes_reserved_space;//requested from
00697                                  // log -- used ONLY for assertions/debugging
00698     bool                         _rolling_back;// true if aborting OR
00699                                  // in rollback_work (which does not change
00700                                  // the xct state).
00701     
00702     bool                         should_consume_rollback_resv(int t) const;
00703     bool                         should_reserve_for_rollback(int t)
00704                                  const {
00705                                     return  ! should_consume_rollback_resv(t);
00706                                  }
00707 private:
00708      volatile int                _in_compensated_op; 
00709         // in the midst of a compensated operation
00710         // use an int because they can be nested.
00711      lsn_t                       _anchor;
00712         // the anchor for the outermost compensated op
00713 
00714      xct_core*                   _core;
00715 
00716 public:
00717     bool                        rolling_back() const { return _rolling_back; }
00718 #if W_DEBUG_LEVEL > 2
00719 private: 
00720     bool                        _had_error;
00721 public:
00722     // Tells if we ever did a partial rollback.
00723     // This state is only needed for certain assertions.
00724     void                        set_error_encountered() { _had_error = true; } 
00725     bool                        error_encountered() const { 
00726                                                return _had_error; }
00727 #else
00728     void                        set_error_encountered() {}
00729     bool                        error_encountered() const {  return false; }
00730 #endif
00731     tid_t                       tid() const { 
00732                                     w_assert1(_tid == _core->_tid);
00733                                     return _tid; }
00734 };
00735 
00736 /**\cond skip */
00737 
00738 // Release anchor on destruction
00739 class auto_release_anchor_t {
00740     bool _compensate;
00741     xct_t* _xct;
00742 public:
00743     auto_release_anchor_t (bool and_compensate) : 
00744         _compensate(and_compensate), _xct(xct())
00745     {}
00746     ~auto_release_anchor_t ()  
00747     {
00748         _xct->release_anchor(_compensate X_LOG_COMMENT_USE("auto_release_anchor_t"));
00749     }
00750 };
00751 // Cause a rollback to the savepoint on destruction
00752 // unless ok() is called, in which case, do not.
00753 class auto_rollback_t {
00754 private:
00755     xct_t* _xd;
00756     lsn_t  _save_pt;
00757     bool   _roll;
00758     static int _count;
00759     int    _test;
00760     int    _line; // debugging
00761     const char *_file; // debugging
00762 public:
00763     // for testing
00764     // every so often we need to fake an eOUTOFLOGSPACE error.
00765     w_rc_t test(int x) { _test=x; 
00766         if(_test && (_count % _test==0)) 
00767              return RC(smlevel_0::eOUTOFLOGSPACE); // will ignore ok() 
00768         return RCOK;
00769     }
00770 
00771 #define AUTO_ROLLBACK_work auto_rollback_t work(__LINE__, __FILE__);
00772     auto_rollback_t(int line, const char *file)
00773         : _xd(xct()), _roll(true), _test(0),
00774         _line(line), _file(file)
00775     {
00776         // we don't care if this faking of error is thread-safe
00777         _count++;
00778         if(_xd) {
00779             // there's no possible error from save_point
00780             W_COERCE(_xd->save_point(_save_pt));
00781         }
00782     }
00783     void ok() { _roll = false; }
00784 
00785     ~auto_rollback_t() { 
00786 
00787         if(_test && (_count % _test==0)) _roll = true; // ignore ok() 
00788         if(_roll && _xd) { 
00789             _xd->set_error_encountered();
00790             W_COERCE(_xd->rollback(_save_pt)); 
00791             INC_TSTAT(internal_rollback_cnt);
00792 #if 0 && W_DEBUG_LEVEL > 0
00793             cerr << "Internal rollback to "  << _save_pt
00794                 << " from " << _line
00795                 << " " << _file
00796                 << endl;
00797 #endif
00798         }
00799     }
00800 };
00801 
00802 /**\endcond skip */
00803 
00804 /*
00805  * Use X_DO inside compensated operations
00806  */
00807 #if X_LOG_COMMENT_ON
00808 #define X_DO1(x,anchor,line)             \
00809 {                           \
00810     w_rc_t __e = (x);       \
00811     if (__e.is_error()) {        \
00812         w_assert3(xct());        \
00813         W_COERCE(xct()->rollback(anchor));        \
00814         xct()->release_anchor(true X_LOG_COMMENT_USE("X_DO1"));    \
00815         return RC_AUGMENT(__e); \
00816     } \
00817 }
00818 #define to_string(x) # x
00819 #define X_DO(x,anchor) X_DO1(x,anchor, to_string(x))
00820 
00821 #else
00822 
00823 #define X_DO(x,anchor)             \
00824 {                           \
00825     w_rc_t __e = (x);       \
00826     if (__e.is_error()) {        \
00827         w_assert3(xct());        \
00828         W_COERCE(xct()->rollback(anchor));        \
00829         xct()->release_anchor(true X_LOG_COMMENT_USE("X_DO"));        \
00830         return RC_AUGMENT(__e); \
00831     } \
00832 }
00833 #endif
00834 
00835 /**\cond skip */
00836 class xct_log_switch_t : public smlevel_0 {
00837     /*
00838      * NB: use sparingly!!!! EVERYTHING DONE UNDER
00839      * CONTROL OF ONE OF THESE IS A CRITICAL SECTION
00840      */
00841     switch_t old_state;
00842 public:
00843     /// Initialize old state
00844     NORET xct_log_switch_t(switch_t s)  : old_state(OFF)
00845     {
00846         if(smlevel_1::log) {
00847             INC_TSTAT(log_switches);
00848             if (xct()) {
00849                 old_state = xct()->set_log_state(s);
00850             }
00851         }
00852     }
00853 
00854     NORET
00855     ~xct_log_switch_t()  {
00856         if(smlevel_1::log) {
00857             if (xct()) {
00858                 xct()->restore_log_state(old_state);
00859             }
00860         }
00861     }
00862 };
00863 
00864 inline
00865 bool xct_t::is_log_on() const {
00866     return (me()->xct_log()->xct_log_is_off() == false);
00867 }
00868 /**\endcond skip */
00869 
00870 /* XXXX This is somewhat hacky becuase I am working on cleaning
00871    up the xct_i xct iterator to provide various levels of consistency.
00872    Until then, the "locking option" provides enough variance so
00873    code need not be duplicated or have deep call graphs. */
00874 
00875 /**\brief Iterator over transaction list.
00876  *
00877  * This is exposed for the purpose of coping with out-of-log-space 
00878  * conditions. See \ref LOGSPACE.
00879  */
00880 class xct_i  {
00881 public:
00882     // NB: still not safe, since this does not
00883     // lock down the list for the entire iteration.
00884     
00885     // FRJ: Making it safe -- all non-debug users lock it down
00886     // manually right now anyway; the rest *should* to avoid bugs.
00887 
00888     /// True if this thread holds the transaction list mutex.
00889     bool locked_by_me() const {
00890         if(xct_t::xlist_mutex_is_mine()) {
00891             W_IFDEBUG1(if(_may_check) w_assert1(_locked);)
00892             return true;
00893         }
00894         return false;
00895     }
00896 
00897     /// Release transaction list mutex if this thread holds it.
00898     void never_mind() {
00899         // Be careful here: must leave in the
00900         // state it was when we constructed this.
00901         if(_locked && locked_by_me()) {
00902             *(const_cast<bool *>(&_locked)) = false; // grot
00903             xct_t::release_xlist_mutex();
00904         }
00905     }
00906     /// Get transaction at cursor.
00907     xct_t* curr() const { return unsafe_iterator.curr(); }
00908     /// Advance cursor.
00909     xct_t* next() { return unsafe_iterator.next(); }
00910 
00911     /**\cond skip */
00912     // Note that this is called to INIT the attribute "locked"
00913     static bool init_locked(bool lockit) 
00914     {
00915         if(lockit) {
00916             W_COERCE(xct_t::acquire_xlist_mutex());
00917         }
00918         return lockit;
00919     }
00920     /**\endcond skip */
00921 
00922     /**\brief Constructor.
00923     *
00924     * @param[in] locked_accesses Set to true if you want this
00925     * iterator to be safe, false if you don't care or if you already
00926     * hold the transaction-list mutex.
00927     */
00928     NORET xct_i(bool locked_accesses)
00929         : _locked(init_locked(locked_accesses)),
00930         _may_check(locked_accesses),
00931         unsafe_iterator(xct_t::_xlist)
00932     {
00933         w_assert1(_locked == locked_accesses);
00934         _check(_locked);
00935     }
00936 
00937     /// Desctructor. Calls never_mind() if necessary.
00938     NORET ~xct_i() { 
00939         if(locked_by_me()) {
00940           _check(true);
00941           never_mind(); 
00942           _check(false);
00943         }
00944     }
00945 
00946 private:
00947     void _check(bool b) const  {
00948           if(!_may_check) return;
00949           if(b) xct_t::assert_xlist_mutex_is_mine(); 
00950           else  xct_t::assert_xlist_mutex_not_mine(); 
00951     }
00952     // FRJ: make sure init_locked runs before we actually create the iterator
00953     const bool            _locked;
00954     const bool            _may_check;
00955     w_list_i<xct_t,queue_based_lock_t> unsafe_iterator;
00956 
00957     // disabled
00958     xct_i(const xct_i&);
00959     xct_i& operator=(const xct_i&);
00960 };
00961     
00962 
00963 /**\cond skip */
00964 inline
00965 xct_t::state_t
00966 xct_t::state() const
00967 {
00968     return _core->_state;
00969 }
00970 
00971 // For use in sm functions that don't allow
00972 // active xct when entered.  These are functions that
00973 // apply to local volumes only.
00974 class xct_auto_abort_t : public smlevel_1 {
00975 public:
00976     xct_auto_abort_t() : _xct(xct_t::new_xct()) {
00977         (void)  _xct->attach_update_thread(); 
00978     }
00979     ~xct_auto_abort_t() {
00980         switch(_xct->state()) {
00981         case smlevel_1::xct_ended:
00982             // do nothing
00983             break;
00984         case smlevel_1::xct_active:
00985         case smlevel_1::xct_freeing_space: // we got an error in commit
00986         case smlevel_1::xct_committing: // we got an error in commit
00987             W_COERCE(_xct->abort());
00988             break;
00989         default:
00990             cerr << "unexpected xct state: " << _xct->state() << endl;
00991             W_FATAL(eINTERNAL);
00992         }
00993         (void)  _xct->detach_update_thread(); 
00994         xct_t::destroy_xct(_xct);
00995     }
00996     rc_t commit() {
00997         // These are only for local txs
00998         // W_DO(_xct->prepare());
00999         W_DO(_xct->commit());
01000         return RCOK;
01001     }
01002     rc_t abort() {W_DO(_xct->abort()); return RCOK;}
01003 
01004 private:
01005     xct_t*        _xct;
01006 };
01007 
01008 
01009 inline
01010 bool
01011 operator>(const xct_t& x1, const xct_t& x2)
01012 {
01013     return (x1.tid() > x2.tid());
01014 }
01015 
01016 inline void
01017 xct_t::SetEscalationThresholds(w_base_t::int4_t toPage, 
01018                 w_base_t::int4_t toStore, 
01019                 w_base_t::int4_t toVolume)
01020 {
01021     if (toPage != dontModifyThreshold)
01022                 escalationThresholds[2] = toPage;
01023     
01024     if (toStore != dontModifyThreshold)
01025                 escalationThresholds[1] = toStore;
01026     
01027     if (toVolume != dontModifyThreshold)
01028                 escalationThresholds[0] = toVolume;
01029 }
01030 
01031 inline void
01032 xct_t::SetDefaultEscalationThresholds()
01033 {
01034     SetEscalationThresholds(smlevel_0::defaultLockEscalateToPageThreshold,
01035             smlevel_0::defaultLockEscalateToStoreThreshold,
01036             smlevel_0::defaultLockEscalateToVolumeThreshold);
01037 }
01038 
01039 inline void
01040 xct_t::GetEscalationThresholds(w_base_t::int4_t &toPage, 
01041                 w_base_t::int4_t &toStore, 
01042                 w_base_t::int4_t &toVolume)
01043 {
01044     toPage = escalationThresholds[2];
01045     toStore = escalationThresholds[1];
01046     toVolume = escalationThresholds[0];
01047 }
01048 
01049 inline const w_base_t::int4_t *
01050 xct_t::GetEscalationThresholdsArray()
01051 {
01052     return escalationThresholds;
01053 }
01054 
01055 inline
01056 xct_t::vote_t
01057 xct_t::vote() const
01058 {
01059     return _core->_vote;
01060 }
01061 
01062 inline
01063 const lsn_t&
01064 xct_t::last_lsn() const
01065 {
01066     return _last_lsn;
01067 }
01068 
01069 inline
01070 void
01071 xct_t::set_last_lsn( const lsn_t&l)
01072 {
01073     _last_lsn = l;
01074 }
01075 
01076 inline
01077 const lsn_t&
01078 xct_t::first_lsn() const
01079 {
01080     return _first_lsn;
01081 }
01082 
01083 inline
01084 void
01085 xct_t::set_first_lsn(const lsn_t &l) 
01086 {
01087     _first_lsn = l;
01088 }
01089 
01090 inline
01091 const lsn_t&
01092 xct_t::undo_nxt() const
01093 {
01094     return _undo_nxt;
01095 }
01096 
01097 inline
01098 void
01099 xct_t::set_undo_nxt(const lsn_t &l) 
01100 {
01101     _undo_nxt = l;
01102 }
01103 
01104 inline
01105 const logrec_t*
01106 xct_t::last_log() const
01107 {
01108     return _last_log;
01109 }
01110 
01111 inline
01112 bool
01113 xct_t::forced_readonly() const
01114 {
01115     return _core->_forced_readonly;
01116 }
01117 
01118 /*********************************************************************
01119  *
01120  *  bool xct_t::is_extern2pc()
01121  *
01122  *  return true iff this tx is participating
01123  *  in an external 2-phase commit protocol, 
01124  *  which is effected by calling enter2pc() on this
01125  *
01126  *********************************************************************/
01127 inline bool            
01128 xct_t::is_extern2pc() 
01129 const
01130 {
01131     // true if is a thread of global tx
01132     return _core->_global_tid != 0;
01133 }
01134 
01135 
01136 inline
01137 const gtid_t*           
01138 xct_t::gtid() const 
01139 {
01140     return _core->_global_tid;
01141 }
01142 
01143 /**\endcond skip */
01144 
01145 /*<std-footer incl-file-exclusion='XCT_H'>  -- do not edit anything below this line -- */
01146 
01147 #endif          /*</std-footer>*/

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7