From fdced7082a9aa49c09de41e7f63b51fc3bf073ef Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Thu, 1 Jul 2010 01:06:13 -0400 Subject: [PATCH] mostly done with a real distributed lock --- client/distlock.h | 124 ++++++++++++++++++++++++++++++++++++++++++++++ s/chunk.cpp | 1 + 2 files changed, 125 insertions(+) create mode 100644 client/distlock.h diff --git a/client/distlock.h b/client/distlock.h new file mode 100644 index 00000000000..d14c1c9cc0f --- /dev/null +++ b/client/distlock.h @@ -0,0 +1,124 @@ +// distlock.h + +/* Copyright 2009 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * distribuetd locking mechanism + */ + +#include "../pch.h" +#include "dbclient.h" +#include "redef_macros.h" + +namespace mongo { + + extern string ourHostname; + + class DistributedLock { + public: + DistributedLock( const ConnectionString& conn , const string& ns , const BSONObj& key , const string& field ) + : _conn(conn), _ns(ns), _key(key.getOwned()), _field(field){ + } + + int getState(){ + return _state.get(); + } + + bool isLocked(){ + return _state.get() != 0; + } + + bool lock_try(){ + // recursive + if ( getState() > 0 ) + return true; + + ScopedDbConnection conn( _conn ); + + { // make sure its there so we can use simple update logic below + BSONObj o = conn->findOne( _ns , _key ); + if ( o.isEmpty() ){ + conn->update( _ns , _key , BSON( "$set" << BSON( _field << BSON( "state" << 0 ) ) ) , 1 ); + } + } + + + BSONObjBuilder b; + b.appendElements( _key ); + b.append( _field + ".state" , 0 ); + + + conn->update( _ns , b.obj() , BSON( "$set" << BSON( _field + ".state" << 1 << "who" << myid() ) ) ); + assert(0); + conn.done(); + } + + void unlock(){ + ScopedDbConnection conn( _conn ); + conn->update( _ns , _key, BSON( "$set" << BSON( _field + ".state" << 0 ) ) ); + conn.done(); + + _state.set( 0 ); + } + + string myid(){ + string s = _myid.get(); + if ( s.empty() ){ + stringstream ss; + ss << ourHostname << ":" << time(0) << ":" << rand(); + s = ss.str(); + _myid.set( s ); + } + + return s; + } + + private: + ConnectionString _conn; + string _ns; + BSONObj _key; + string _field; + ThreadLocalValue _state; + ThreadLocalValue _myid; + }; + + class dist_lock_try { + public: + + dist_lock_try( DistributedLock * lock ) + : _lock(lock){ + _got = _lock->lock_try(); + } + + ~dist_lock_try(){ + if ( _got ){ + _lock->unlock(); + } + } + + bool got() const { + return _got; + } + + private: + DistributedLock * _lock; + bool _got; + + }; + +} + diff --git a/s/chunk.cpp b/s/chunk.cpp index bb262d4d09b..9702c5382f8 100644 --- a/s/chunk.cpp +++ b/s/chunk.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "../util/unittest.h" #include "../client/connpool.h" +#include "../client/distlock.h" #include "../db/queryutil.h" #include "cursors.h" #include "strategy.h"