latch.cpp

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 // -*- mode:c++; c-basic-offset:4 -*-
00025 /*<std-header orig-src='shore'>
00026 
00027  $Id: latch.cpp,v 1.49 2010/12/08 17:37:34 nhall Exp $
00028 
00029 SHORE -- Scalable Heterogeneous Object REpository
00030 
00031 Copyright (c) 1994-99 Computer Sciences Department, University of
00032                       Wisconsin -- Madison
00033 All Rights Reserved.
00034 
00035 Permission to use, copy, modify and distribute this software and its
00036 documentation is hereby granted, provided that both the copyright
00037 notice and this permission notice appear in all copies of the
00038 software, derivative works or modified versions, and any portions
00039 thereof, and that both notices appear in supporting documentation.
00040 
00041 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00042 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00043 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00044 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00045 
00046 This software was developed with support by the Advanced Research
00047 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00048 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00049 Further funding for this work was provided by DARPA through
00050 Rome Research Laboratory Contract No. F30602-97-2-0247.
00051 
00052 */
00053 
00054 #include "w_defines.h"
00055 
00056 /*  -- do not edit anything above this line --   </std-header>*/
00057 
00058 #ifdef __GNUC__
00059 #pragma implementation
00060 #endif
00061 
00062 #include "w.h"
00063 #include "sthread.h"
00064 #include "latch.h"
00065 #include "w_debug.h"
00066 
00067 #include <cstring>
00068 #include <sthread_stats.h>
00069 #include <list>
00070 #include <algorithm>
00071 
00072 const char* const  latch_t::latch_mode_str[3] = { "NL", "SH", "EX" };
00073 
00074 
00075 latch_t::latch_t(const char* const desc) :
00076     _total_count(0) 
00077 {
00078     setname(desc);
00079 }
00080 
00081 latch_t::~latch_t()
00082 {
00083 #if W_DEBUG_LEVEL > 1
00084     int t = _total_count;
00085     // do this just to get the symbol to remain 
00086     if(t) {
00087         fprintf(stderr, "t=%d\n", t);
00088     }
00089     w_assert2(t == 0);// BUG_SEMANTICS_FIX
00090 
00091     w_assert2(mode() == LATCH_NL);
00092     w_assert2(num_holders() == 0);
00093 #endif
00094 }
00095 
00096 
00097 /**\var static __thread latch_holder_t* latch_holder_t::thread_local_holders;
00098  * \brief Linked list of all latches held by this thread.
00099  * \ingroup TLS
00100  *
00101  * \details
00102  * Every time we want to grab a latch,
00103  * we have to create a latch_holder_t; we do that with the
00104  * holder_search class, which searches the per-thread list below
00105  * to make sure we `(this thread) don't already hold the latch and 
00106  * if not, it creates a new latch_holder_t for the new latch acquisition,
00107  * and stuffs the latch_holder_t in this list.  
00108  * If we do already have hold the latch in some capacity, the 
00109  * holder_search returns that existing latch_holder_t.
00110  * So we can tell if this thread holds a given latch, and we can
00111  * find all latches held by this thread, but we can't find
00112  * all the holders of a given latch.
00113  *
00114  * \sa latch_holder_t
00115  */
00116 __thread latch_holder_t* latch_holder_t::thread_local_holders(NULL);
00117 
00118 /**\var static __thread latch_holder_t* latch_holder_t::thread_local_freelist;
00119  * \brief Pool of unused latch_holder_t instances.
00120  * \ingroup TLS
00121  *
00122  * \details
00123  * Ready for recycling.  These structures are first taken from the global heap
00124  * but put on this list for reuse rather than ::free-ed.
00125  * When the thread is destroyed, the items on this list are returned
00126  * to the global heap.
00127  *
00128  * \sa latch_holder_t
00129  */
00130 __thread latch_holder_t* latch_holder_t::thread_local_freelist(NULL);
00131 
00132 /**\brief The list-handling class for latch_holder_t instances.
00133  *
00134  * \details
00135  * Really, all this does is provide an iterator and a means to
00136  * insert (push_front)  and remove (unlink) these things.
00137  *
00138  * The list contents are always instances of latch_holder_t, which 
00139  * have an internal link for creating the list.
00140  */
00141 class holder_list 
00142 {
00143     latch_holder_t* &_first;
00144 public:
00145     holder_list(latch_holder_t* &first) : _first(first) { }
00146 
00147     /**\brief Iterator over a list of latch_holder_t structures */
00148     struct iterator {
00149         latch_holder_t* _cur;
00150         public:
00151 
00152         /// Construct an iterator starting with the given latch_holder_t.
00153         explicit iterator(latch_holder_t* cur) : _cur(cur) { }
00154 
00155         /// Get current.
00156         operator latch_holder_t*() const { return _cur; }
00157 
00158         /// Get current.
00159         latch_holder_t* operator->() const { return *this; }
00160 
00161         ///  Make iterator point to next.
00162         iterator &operator++() { _cur = _cur->_next; return *this; }
00163 
00164         ///  Make iterator point to next.
00165         iterator operator++(int) { return ++iterator(*this); }
00166     };
00167 
00168     /// Dereferencing this iterator brings us to the first item in the list.
00169     iterator begin() { return iterator(_first); }
00170 
00171     /// Dereferencing this iterator brings us past the last item in any list.
00172     iterator end() { return iterator(NULL); }
00173 
00174     /// Insert h at the front of this list.
00175     void push_front(latch_holder_t* h) {
00176         h->_next = _first;
00177         if(_first) _first->_prev = h;
00178         h->_prev = NULL;
00179         _first = h;
00180     }
00181 
00182     /// Remove whatever is the current item for the given iterator.
00183     latch_holder_t* unlink(iterator const &it) {
00184         if(it->_next)
00185             it->_next->_prev = it->_prev;
00186         
00187         if(it->_prev) 
00188             it->_prev->_next = it->_next;
00189         else 
00190             _first = it->_next;
00191 
00192         // now it's orphaned...
00193         return it;
00194     }
00195 };
00196 
00197 /**\class holders_print
00198  * \brief For debugging only.
00199  *
00200  * \details
00201  *
00202  * Constructor looks through all the holders in the 
00203  * implied list starting with the latch_holder_t passed in as the sole
00204  * constructor argument.  
00205  *
00206  * It prints info about each latch_holder_t in the list.
00207  *
00208  * \sa latch_holder_t.
00209  */
00210 class  holders_print 
00211 {
00212 private:
00213     holder_list _holders;
00214     void print(holder_list holders)
00215     {
00216         holder_list::iterator it=holders.begin();
00217         for(; it!=holders.end() && it->_latch;  ++it) 
00218         {
00219             it->print(cerr);
00220         }
00221     }
00222 public:
00223     holders_print(latch_holder_t *list) 
00224     : _holders(list)
00225     {
00226         print(_holders);
00227     }
00228 };
00229 
00230 /**\class holder_search
00231  * \brief Finds all latches held by this thread.
00232  *
00233  * \details
00234  * Searches a thread-local list for a latch_holder_t that is a
00235  * reference to the given latch_t.
00236  *
00237  * \sa latch_holder_t.
00238  */
00239 class holder_search 
00240 {
00241 public:
00242     /// find holder of given latch in given list
00243     static holder_list::iterator find(holder_list holders, latch_t const* l) 
00244     {
00245         holder_list::iterator it=holders.begin();
00246         for(; it!=holders.end() && it->_latch != l; ++it) ;
00247         return it;
00248     }
00249 
00250     /// count # times we find a given latch in the list. For debugging, asserts.
00251     static int count(holder_list holders, latch_t const* l) 
00252     {
00253         holder_list::iterator it=holders.begin();
00254         int c=0;
00255         for(; it!=holders.end(); ++it) if(it->_latch == l) c++;
00256         return c;
00257     }
00258 
00259 private:
00260     holder_list _holders;
00261     latch_holder_t* &_freelist;
00262     holder_list::iterator _end;
00263     holder_list::iterator _it;
00264 
00265 public:
00266     /// Insert latch_holder_t for given latch if not already there.
00267     holder_search(latch_t const* l)
00268         : _holders(latch_holder_t::thread_local_holders),
00269           _freelist(latch_holder_t::thread_local_freelist),
00270           _end(_holders.end()),
00271           _it(find(_holders, l))
00272     {
00273         // if we didn't find the latch in the list,
00274         // create a new latch_holder_t (with mode LATCH_NL)
00275         // to return, just so that the value() method always
00276         // returns a non-null ptr.  It might be used, might not.
00277         if(_it == _end) {
00278             latch_holder_t* h = _freelist;
00279             if(h) _freelist = h->_next;
00280             // need to clear out the latch either way
00281             if(h)
00282                 // h->latch_holder_t(); // reinit
00283                 h = new(h) latch_holder_t();
00284             else
00285                 h = new latch_holder_t;
00286             _holders.push_front(h);
00287             _it = _holders.begin();
00288         }
00289         w_assert2(count(_holders, l) <= 1);
00290     }
00291 
00292     ~holder_search() 
00293     {
00294         if(_it == _end || _it->_mode != LATCH_NL)
00295             return;
00296         
00297         // don't hang onto it in the holders list  if it's not latched.
00298         latch_holder_t* h = _holders.unlink(_it);
00299         h->_next = _freelist;
00300         _freelist = h;
00301     }
00302 
00303     latch_holder_t* operator->() { return this->value(); }
00304 
00305     latch_holder_t* value() { return (_it == _end)? 
00306         (latch_holder_t *)(NULL) : &(*_it); }
00307 }; // holder_search
00308 
00309 /**\cond skip */
00310 // For debugging purposes, let's string together all the thread_local
00311 // lists so that we can print all the latches and their
00312 // holders.   smthread_t calls on_thread_init and on_thread_destroy.
00313 #include <map>
00314 typedef std::map<sthread_t*, latch_holder_t**> holder_list_list_t;
00315 static holder_list_list_t holder_list_list;
00316 
00317 // It's not that this needs to be queue-based, but we want to avoid
00318 // pthreads API use directly as much as possible.
00319 static queue_based_block_lock_t    holder_list_list_lock;
00320 
00321 void latch_t::on_thread_init(sthread_t *who) 
00322 {
00323     CRITICAL_SECTION(cs, holder_list_list_lock);
00324     holder_list_list.insert(std::make_pair(who, 
00325                 &latch_holder_t::thread_local_holders));
00326 }
00327 
00328 void latch_t::on_thread_destroy(sthread_t *who) 
00329 {
00330     {
00331        CRITICAL_SECTION(cs, holder_list_list_lock);
00332        holder_list_list.erase(who);
00333     }
00334 
00335     w_assert3(!latch_holder_t::thread_local_holders);
00336     latch_holder_t* freelist = latch_holder_t::thread_local_freelist;
00337     while(freelist) {
00338         latch_holder_t* node = freelist;
00339         freelist = node->_next;
00340         delete node;
00341     }
00342     latch_holder_t::thread_local_freelist = NULL;
00343 }
00344 /**\endcond skip */
00345 
00346 
00347 w_rc_t 
00348 latch_t::latch_acquire(latch_mode_t mode, sthread_t::timeout_in_ms timeout) 
00349 {
00350     w_assert1(mode != LATCH_NL); 
00351     holder_search me(this);
00352     return _acquire(mode, timeout, me.value());
00353 }
00354 
00355 w_rc_t
00356 latch_t::upgrade_if_not_block(bool& would_block)
00357 {
00358     DBGTHRD(<< " want to upgrade " << *this );
00359     holder_search me(this);
00360     
00361     // should already hold the latch
00362     w_assert3(me.value() != NULL);
00363     
00364     // already hold EX? DON'T INCREMENT THE COUNT!
00365     if(me->_mode == LATCH_EX) {
00366         would_block = false;
00367         return RCOK;
00368     }
00369     
00370     w_rc_t rc = _acquire(LATCH_EX, WAIT_IMMEDIATE, me.value());
00371     if(rc.is_error()) {
00372         // it never should have tried to block
00373         w_assert3(rc.err_num() != sthread_t::stTIMEOUT);
00374         if(rc.err_num() != sthread_t::stINUSE) 
00375             return RC_AUGMENT(rc);
00376     
00377         would_block = true;
00378     }
00379     else {
00380         // upgrade should not increase the lock count
00381         atomic_dec_uint(&_total_count); 
00382         me->_count--;
00383         would_block = false;
00384     }
00385     return RCOK;
00386 }
00387 
00388 int latch_t::latch_release() 
00389 {
00390     holder_search me(this);
00391     // we should already hold the latch!
00392     w_assert2(me.value() != NULL);
00393     return _release(me.value());
00394 }
00395 
00396 w_rc_t latch_t::_acquire(latch_mode_t new_mode, 
00397     sthread_t::timeout_in_ms timeout, 
00398     latch_holder_t* me) 
00399 {
00400     FUNC(latch_t::_acquire);
00401     DBGTHRD( << "want to acquire in mode " 
00402             << W_ENUM(new_mode) << " " << *this
00403             );
00404     w_assert2(new_mode != LATCH_NL);
00405     w_assert2(me);
00406 
00407     bool is_upgrade = false;
00408     if(me->_latch == this) 
00409     {
00410         // we already hold the latch
00411         w_assert2(me->_mode != LATCH_NL);
00412         w_assert2(mode() == me->_mode); 
00413         // note: _mode can't change while we hold the latch!
00414         if(mode() == LATCH_EX) {
00415             w_assert2(num_holders() == 1);
00416             // once we hold it in EX all later acquires default to EX as well
00417             new_mode = LATCH_EX; 
00418         } else {
00419             w_assert2(num_holders() >= 1);
00420         }
00421         if(me->_mode == new_mode) {
00422             DBGTHRD(<< "we already held latch in desired mode " << *this);
00423             atomic_inc_uint(&_total_count);// BUG_SEMANTICS_FIX
00424             me->_count++; // thread-local
00425             // fprintf(stderr, "acquire latch %p %dx in mode %s\n", 
00426             //        this, me->_count, latch_mode_str[new_mode]);
00427 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00428             // These are counted in bf statistics.
00429             // but if we don't count them here, we will get
00430             // a misleading impression of the wait counts
00431             // is_upgrade is figured w/o consideraton whether request is
00432             // conditional/unconditional, but we consider it
00433             // uncondl because the unconditional case is 
00434             // the one we're trying to understand in the callers
00435             // (bf find, bf scan, btree latch
00436             INC_STH_STATS(latch_uncondl_nowait);
00437 #endif
00438             return RCOK;
00439         } else if(new_mode == LATCH_EX && me->_mode == LATCH_SH) {
00440             is_upgrade = true;
00441         }
00442     } else {
00443         // init 'me' (latch holder) for the critical section
00444         me->_latch = this;
00445         me->_mode = LATCH_NL;
00446         me->_count = 0;
00447     }
00448 
00449     // have to acquire for real
00450     
00451     if(is_upgrade) {
00452         // to avoid deadlock,
00453         // never block on upgrade 
00454         if(!_lock.attempt_upgrade())
00455             return RC(sthread_t::stINUSE);
00456 
00457         w_assert2(me->_count > 0);
00458         w_assert2(new_mode == LATCH_EX);
00459         me->_mode = new_mode;
00460 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00461         // These are counted in bf statistics.
00462         // but if we don't count them here, we will get
00463         // a misleading impression of the wait counts
00464         // is_upgrade is figured w/o consideraton whether request is
00465         // conditional/unconditional, but we consider it
00466         // uncondl because the unconditional case is 
00467         // the one we're trying to understand in the callers
00468         // (bf find, bf scan, btree latch
00469         INC_STH_STATS(latch_uncondl_nowait);
00470 #endif
00471     } else {
00472         if(timeout == WAIT_IMMEDIATE) {
00473             INC_STH_STATS(needs_latch_condl);
00474             bool success = (new_mode == LATCH_SH)? 
00475                 _lock.attempt_read() : _lock.attempt_write();
00476             if(!success)
00477                 return RC(sthread_t::stTIMEOUT);
00478             INC_STH_STATS(latch_condl_nowait);
00479         }
00480         else {
00481             // forever timeout
00482             INC_STH_STATS(needs_latch_uncondl);
00483             if(new_mode == LATCH_SH) {
00484 // NOTE: These stats are questionable in their
00485 // heiseneffect as well as in the fact that we might
00486 // not wait in the _lock.acquire_{read,write} call
00487 // after the attempt- call. Nevertheless, they might
00488 // help us in some instances to understand where the
00489 // contention is, and are under compiler control for
00490 // this reason.
00491 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00492                 if(_lock.attempt_read()) {
00493                     INC_STH_STATS(latch_uncondl_nowait);
00494                 } else
00495 #endif
00496                 _lock.acquire_read();
00497             }
00498             else {
00499                 w_assert2(new_mode == LATCH_EX);
00500                 w_assert2(me->_count == 0);
00501 #if defined(EXPENSIVE_LATCH_COUNTS) && EXPENSIVE_LATCH_COUNTS>0
00502                 if(_lock.attempt_write()) {
00503                     INC_STH_STATS(latch_uncondl_nowait);
00504                 } else 
00505 #endif
00506                 _lock.acquire_write();
00507             }
00508         }
00509         w_assert2(me->_count == 0);
00510         me->_mode = new_mode;
00511     }
00512     atomic_inc_uint(&_total_count);// BUG_SEMANTICS_FIX
00513     me->_count++;// BUG_SEMANTICS_FIX
00514     DBGTHRD(<< "acquired " << *this );
00515     return RCOK;  
00516 }
00517 
00518 
00519 int 
00520 latch_t::_release(latch_holder_t* me)
00521 {
00522     FUNC(latch_t::release);
00523     DBGTHRD(<< "want to release " << *this );
00524 
00525     w_assert2(me->_latch == this);
00526     w_assert2(me->_mode != LATCH_NL);
00527     w_assert2(me->_count > 0);
00528 
00529     atomic_dec_uint(&_total_count); 
00530     if(--me->_count) {
00531         DBGTHRD(<< "was held multiple times -- still " << me->_count << " " << *this );
00532         return me->_count;
00533     }
00534     
00535     if(me->_mode == LATCH_SH) {
00536         w_assert2(_lock.has_reader());
00537         _lock.release_read();
00538     }
00539     else {
00540         w_assert2(_lock.has_writer());
00541         _lock.release_write();
00542     }
00543     me->_mode = LATCH_NL;
00544     return 0;
00545 }
00546 
00547 void latch_t::downgrade() {
00548     holder_search me(this);
00549     // we should already hold the latch!
00550     w_assert3(me.value() != NULL);
00551     _downgrade(me.value());
00552 }
00553 
00554 void 
00555 latch_t::_downgrade(latch_holder_t* me)
00556 {
00557     FUNC(latch_t::downgrade);
00558     DBGTHRD(<< "want to downgrade " << *this );
00559 
00560     w_assert3(me->_latch == this);
00561     w_assert3(me->_mode == LATCH_EX);
00562     w_assert3(me->_count > 0);
00563     
00564     _lock.downgrade();
00565     me->_mode = LATCH_SH;
00566     
00567 }
00568 
00569 void latch_holder_t::print(ostream &o) const
00570 {
00571     o << "Holder " << latch_t::latch_mode_str[int(_mode)] 
00572         << " cnt=" << _count 
00573     << " threadid/" << ::hex << w_base_t::uint8_t(_threadid) 
00574     << " latch:";
00575     if(_latch) {
00576         o  << *_latch << endl;
00577     } else { 
00578         o  << "NULL" << endl;
00579     }
00580 }
00581 
00582 // return the number of times the latch is held by this thread 
00583 // or 0 if I do not hold the latch
00584 // There should never be more than one holder structure for a single
00585 // latch.
00586 int
00587 latch_t::held_by_me() const 
00588 {
00589     holder_search me(this);
00590     return me.value()? me->_count : 0;
00591 }
00592 
00593 bool
00594 latch_t::is_mine() const {
00595     holder_search me(this);
00596     return me.value()? (me->_mode == LATCH_EX) : false;
00597 }
00598 
00599 // NOTE: this is not safe, but it can be used by unit tests
00600 // and for debugging
00601 #include <w_stream.h>
00602 ostream &latch_t::print(ostream &out) const
00603 {
00604     out <<    "latch(" << this << "): " << name();
00605     out << " held in " << latch_mode_str[int(mode())] << " mode ";
00606     out << "by " << num_holders() << " threads " ;
00607     out << "total " << latch_cnt() << " times " ;
00608     out << endl;
00609     return out;
00610 }
00611 
00612 
00613 ostream& operator<<(ostream& out, const latch_t& l)
00614 {
00615     return l.print(out);
00616 }
00617 
00618 // For use in debugger:
00619 void print_latch(const latch_t *l)
00620 {
00621     if(l != NULL) l->print(cerr);
00622 }
00623 
00624 // For use in debugger:
00625 void print_my_latches()
00626 {
00627     FUNC(print_my_latches);
00628     holders_print all(latch_holder_t::thread_local_holders);
00629 }
00630 
00631 void print_all_latches()
00632 {
00633     FUNC(print_all_latches);
00634 // Don't protect: this is for use in a debugger.
00635 // It's absolutely dangerous to use in a running
00636 // storage manager, since these lists will be
00637 // munged frequently. 
00638     int count=0;
00639     {
00640         holder_list_list_t::iterator  iter;
00641         for(iter= holder_list_list.begin(); 
00642              iter != holder_list_list.end(); 
00643              iter ++) count++;
00644     }
00645     holder_list_list_t::iterator  iter;
00646     cerr << "ALL " << count << " LATCHES {" << endl;
00647     for(iter= holder_list_list.begin(); 
00648          iter != holder_list_list.end(); iter ++)
00649     {
00650         DBG(<<"");
00651         sthread_t* who = iter->first;
00652         DBG(<<" who " << (void *)(who));
00653         latch_holder_t **whoslist = iter->second;
00654         DBG(<<" whoslist " << (void *)(whoslist));
00655         if(who) {
00656         cerr << "{ Thread id:" << ::dec << who->id 
00657          << " @ sthread/" << ::hex << w_base_t::uint8_t(who)
00658          << " @ pthread/" << ::hex << w_base_t::uint8_t(who->myself())
00659          << endl << "\t";
00660         } else {
00661         cerr << "{ empty }"
00662          << endl << "\t";
00663         }
00664         DBG(<<"");
00665         holders_print whose(*whoslist); 
00666         cerr <<  "} " << endl << flush;
00667     }
00668     cerr <<  "}" << endl << flush ;
00669 }

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