Here's one I hacked together a while back, though, as I said before, I
recommend using something better suited to the job...  BTW, this thing uses
a few of our utility classes, but it should be very simple to drop in
replacements.

public class GlobalLock
{
    public GlobalLock(String lockType, String resourceId)
    {
        if (StringUtils.isBlank(lockType))
            throw new NullPointerException("Empty lock type");

        if (StringUtils.isBlank(resourceId))
            throw new NullPointerException("Empty resource id");

        _globalId = StringUtil.toHexString((lockType +
resourceId).getBytes()) +":GlobalLock";

        while(_value == 0)
            _value = RandomUtils.nextLong();

        _acquired = false;
    }

    public GlobalLock lock()
    {
        if (_acquired)
            return this;

        // Lock duration 20sec
        // tries to acquire lock for 21sec
        // obviously this is a far from perfect hack

        final int LOCK_DURATION_SECS = 20;
        final int SLEEP_TIME_MILLIS = 100;
        final int MAX_TRIES = 210; // max number of attempts to acquire lock

        MemcachedClient mc = FotologMemCache.getFotolog();
        for(int numTries = 0; numTries < MAX_TRIES; numTries++)
        {
            if (_log.isInfoEnabled()) _log.info("locking "+_globalId);
            try
            {
                CASValue<Object> mcVal = mc.gets(_globalId);

                if (mcVal == null)
                {
                    _acquired = mc.add(_globalId, LOCK_DURATION_SECS,
_value).get();
                }
                else if ( ((Long)mcVal.getValue()).longValue() == 0 )
                {
                    CASResponse casResp = mc.cas(_globalId, mcVal.getCas(),
_value);
                    _acquired = (casResp == CASResponse.OK);
                }
                else
                {
                    if (_log.isInfoEnabled()) _log.info("waiting for another
process to finish: "+_globalId + ":" + mcVal.getValue());
                }
            }
            catch (Exception e)
            {
                _log.error(e.getMessage());
            }

            if (_acquired)
                return this;

            try { Thread.sleep(SLEEP_TIME_MILLIS); } catch
(InterruptedException ie) {/**/} // don't 'busywait'
        }

        throw new GlobalLockException("Unable to lock [" + _globalId + "]
after " + MAX_TRIES + " attempts");
    }


    /** Unlocks ALL of the resources locked with lock().
     * Never fails, so doesn't require additional try/catch if you are
calling it from some other 'finally'
     */
    public void unlock()
    {
        if (_acquired)
        {
            _acquired = false;

            MemcachedClient mc = FotologMemCache.getFotolog();
            CASValue<Object> mcVal = mc.gets(_globalId);

            if (mcVal == null)
            {
                // nothing to do, val already expired
                if (_log.isInfoEnabled()) _log.info("already expired: " +
_globalId + ":" + _value);
                return;
            }
            else if ( ((Long)mcVal.getValue()).longValue() == _value )
            {
                mc.cas(_globalId, mcVal.getCas(), 0l); // reset but only if
it matches our val
            }
            else
            {
                _log.error("failed to unlock: " + _globalId + ":" + _value);
            }
        }
    }


    private static Logger _log = Logger.getLogger(GlobalLock.class);

    private String _globalId;
    private long _value;
    private boolean _acquired;
}

On Tue, Feb 1, 2011 at 1:40 PM, Roberto Spadim <robe...@spadim.com.br>wrote:

> LOCK should be something like this:
>
> <?php
> // type=0 -> unlock
> // type=1 -> lock
> // client_name must change (use sessionID + username)
> function
> memcache_flock($memcache_obj,$key,$type=0,$client_name='1',$timeout=0){
>        $ret=memcache_add($memcache_obj,$key,$client_name,false,$timeout);
>        if($ret==true){
>                if($type==0)    // delete
>                        memcache_del($memcache_obj,$key);
>                return(true);
>        }
>        $cur_cli=memcache_get($memcache_obj,$key);
>        if(is_string($cur_cli) && $cur_cli!=''){ // if ='' no user!
>                if($cur_cli !== $client_name){
>                        // it's not our lock
>                        if(check_user_online_function()) // http session
> function (if want
> http session integration), for memcached it´s like (true)
>                                return($cur_cli);       // return current
> lock client_name
>                }
>                // our lock!
>        }else{
>                // replace, autocorrect a wrong usage
>                memcache_replace($memcache_obj, $key, $client_name, false,
> $timeout);
>        }
>        if($type==0)    // delete?
>                memcache_del($memcache_obj,$key);
>        return(true);
> }
> ?>
>
>
>
>
> 2011/2/1 Adam Lee <a...@fotolog.biz>:
> > there are some excellent solutions out there already. check out, for
> > example, zookeeper.
> >
> > awl
> >
> > On Jan 29, 2011 3:32 PM, "rspadim" <rspa...@gmail.com> wrote:
> >> hi guys, there's a async replication project (repcached) that is very
> >> interesting, could we implement it in main source code? at compile
> >> time we could select from repcached or memcached
> >> could we make it sync and/or async?
> >> http://repcached.sourceforge.net/
> >>
> >>
> =================================================================================
> >> there's some non volatile solutions too that's very interesting
> >> (memcachedb), for low memory computers we can use disk
> >> could we implement it in main source code too?
> >> http://memcachedb.org/
> >>
> >>
> >>
> =================================================================================
> >> another, now !NEW! feature...
> >>
> >> i was looking for a *DISTRIBUTED LOCK MANAGER*, but i only found
> >> kernel linux lock manager, that's based on file system (flock)
> >> could we implement a lock manager at memcached?
> >>
> >> what lock manager do?
> >> client send: KEY NAME, lock type+client name (KEY VALUE), key timeout,
> >> wait lock timeout (infinity/seconds)
> >> (this can be implement in memcached protocol without many
> >> modifications!!!)
> >> server side function:
> >> 1)seek if client can have this lock
> >> 2)wait lock timeout... (this is a problem since we can have a very big
> >> wait time...)
> >> 3) if client disconect exit do while
> >> 4) yes we have the lock => change key value (give this lock to
> >> client), exit do
> >> 5) no we don't have the lock, exit do
> >> 6) end of do while... return key value: lock type + client name (like
> >> a get command)
> >>
> >> ideas:
> >> 1)maybe a separated memory size? we can run two separated servers, one
> >> for keys another for lock function (make command line options: just
> >> lock system, objects only system or both)
> >>
> >> 2)this type of key is diferent from memcached key cache objects,
> >> that's obvious
> >>
> >> but........ is managed with same functions... (get, list, etc)
> >> but........
> >> all write/delete functions can't be done, they MUST be done by LOCK
> >> (the new) function,
> >> DELETE/UNLOCK function is a LOCK function with lock type=0 (unlock)
> >> read can be done by get and will return current client lock name and
> >> lock type (get command)
> >>
> >>
> >>
> >> *WHY THIS FEATURE?*
> >> i didn't found a distributed lock manager for user space (not kernel
> >> space) with easy to implement protocol, and many program languages,
> >> and a very mature server and protocol.
> >> =(
> >>
> >> but with this feature...
> >> I DON'T NEED A SAMBA/NFS SERVER FOR NON FILESYSTEM LOCKING!!!!! \o/
> >> I WILL NEVER USE FLOCK() AGAIN!!! \o/ !!!
> >>
> >> I JUST NEED:
> >> MYSQL+MEMCACHED+ (APACHE+CGI/PHP/JAVA/PERL/PYTHON)
> >> for any cluster solution, no more filesystem!!!
> >>
> >> NO MORE FILESYSTEM REPLICATIONS (DRBD, NBD+RAID) FOR MY HIGH
> >> AVAIBILITY / CLUSTER SOLUTION!!!!!
> >> WE CAN USE REPCACHED (WE NEED A SYNC MODE)....
> >>
> >> THINK ABOUT IT!!!
> >> REPLICATION + FLOCK!!!!! IT'S A VERY VERY VERY NICE FEATURE!!!!!
> >>
> >> ====================
> >> type of object (1bit) default / lock manager can be putted on key
> >> options/flags!!!
> >> inside key value, we can put:
> >> lock type(3 bits)
> >> client name (a variable length, many bytes)
> >>
> >> http://en.wikipedia.org/wiki/Distributed_lock_manager
> >> from wikipedia, TYPE OF LOCKS:
> >> * Null Lock (NL). Indicates interest in the resource, but does not
> >> prevent other processes from locking it. It has the advantage that the
> >> resource and its lock value block are preserved, even when no
> >> processes are locking it.
> >> * Concurrent Read (CR). Indicates a desire to read (but not
> >> update) the resource. It allows other processes to read or update the
> >> resource, but prevents others from having exclusive access to it. This
> >> is usually employed on high-level resources, in order that more
> >> restrictive locks can be obtained on subordinate resources.
> >> * Concurrent Write (CW). Indicates a desire to read and update the
> >> resource. It also allows other processes to read or update the
> >> resource, but prevents others from having exclusive access to it. This
> >> is also usually employed on high-level resources, in order that more
> >> restrictive locks can be obtained on subordinate resources.
> >> * Protected Read (PR). This is the traditional share lock, which
> >> indicates a desire to read the resource but prevents other from
> >> updating it. Others can however also read the resource.
> >> * Protected Write (PW). This is the traditional update lock, which
> >> indicates a desire to read and update the resource and prevents others
> >> from updating it. Others with Concurrent Read access can however read
> >> the resource.
> >> * Exclusive (EX). This is the traditional exclusive lock which
> >> allows read and update access to the resource, and prevents others
> >> from having any access to it.
> >>
> >> NEW LOCK FUNCTION:
> >>
> >> LOCK <key><lock_type><client name><timeout><wait lock timeout>
> >>
> >> key: key name
> >> <lock_type+client_name>=key value
> >>
> >> lock_type:
> >> NL = 0
> >> CR = 1
> >> CW = 2
> >> PR = 3
> >> PW = 4
> >> EX = 5
> >>
> >> client name: any value
> >> timeout: any number, 0=infinity
> >> wait lock timeout: wait lock time, 0=infinity
> >>
> >> how lock works: (see that lock type is only 0 or !=0 in this logic...)
> >> i will use <sent xxxx> for user new value, and <current xxx> for the
> >> current server value
> >>
> >> if key don't exists, create
> >> do{
> >> if ((sent_lock_type = 0 and sent_client_name = current_client_name)
> >> or key_timed_out==1)
> >> remove key (delete)
> >> send null lock and sent_client_name information
> >> exit function
> >> }else if (sent lock type = (1 or 2 or 3 or 4 or 5), and current user
> >> = sent user)
> >> set
> >> current_client_name,current_lock_type=sent_client_name,sent_lock_type
> >> exit do
> >> }else{
> >> if wait lock time < time waiting lock to occur
> >> exit do
> >> }
> >> }while(1)
> >> send current_lock_type and sent_client_name
> >> exit function
> >>
> >>
> >> thanks guys!!!
> >
>
>
>
> --
> Roberto Spadim
> Spadim Technology / SPAEmpresarial
>



-- 
awl

Reply via email to