Hi Stack and Ryan, Thanks for your advices. I knew using row lock wasn't ideal, but I couldn't find an appropriate atomic operation to do Compare And Swap.
So, thanks Stack for helping me to find it. I found incrementColumnValue() atomic operation just works for me since it automatically initializes the column value with 0 when the column doesn't exist. I cat try to increment the column value by 1, and if it returns 1, I can be sure that I'm the first one who has created the column and row. So, my updated code is much simpler and now lock-free. =============================================== def insert(table: HTable, put: Put): Unit = { val count = table.incrementColumnValue(put.getRow, family, uniqueQual, 1) if (count == 1) { table.put(put) } else { throw new DuplicateRowException("Tried to insert a duplicate row: " + Bytes.toString(put.getRow)) } } =============================================== Thanks, Tatsuya 2010/4/29 Ryan Rawson <ryano...@gmail.com>: > I would strongly discourage people from building on top of > lockRow/unlockRow. The problem is if a row is not available, lockRow > will hold a responder thread and you can end up with a deadlock > because the lock holder won't be able to unlock. Sure the expiry > system kicks in, but 60 seconds is kind of infinity in database terms > :-) > > I would probably go with either ICV or CAS to build the tools you > want. With CAS you can accomplish a lot of things locking > accomplishes, but more efficiently. > > On Wed, Apr 28, 2010 at 9:42 AM, Stack <st...@duboce.net> wrote: >> Would the incrementValue [1] work for this? >> St.Ack >> >> 1. >> http://hadoop.apache.org/hbase/docs/r0.20.3/api/org/apache/hadoop/hbase/client/HTable.html#incrementColumnValue%28byte[],%20byte[],%20byte[],%20long%29 >> >> On Wed, Apr 28, 2010 at 7:40 AM, Tatsuya Kawano >> <tatsuy...@snowcocoa.info> wrote: >>> Hi, >>> >>> I'd like to implement unique row ID constraint (like the primary key >>> constraint in RDBMS) in my application framework. >>> >>> Here is a code fragment from my current implementation (HBase >>> 0.20.4rc) written in Scala. It works as expected, but is there any >>> better (shorter) way to do this like checkAndPut()? I'd like to pass >>> a single Put object to my function (method) rather than passing rowId, >>> family, qualifier and value separately. I can't do this now because I >>> have to give the rowLock object when I instantiate the Put. >>> >>> =============================================== >>> def insert(table: HTable, rowId: Array[Byte], family: Array[Byte], >>> qualifier: Array[Byte], value: >>> Array[Byte]): Unit = { >>> >>> val get = new Get(rowId) >>> >>> val lock = table.lockRow(rowId) // will expire in one minute >>> try { >>> if (table.exists(get)) { >>> throw new DuplicateRowException("Tried to insert a duplicate row: " >>> + Bytes.toString(rowId)) >>> >>> } else { >>> val put = new Put(rowId, lock) >>> put.add(family, qualifier, value) >>> >>> table.put(put) >>> } >>> >>> } finally { >>> table.unlockRow(lock) >>> } >>> >>> } >>> =============================================== >>> >>> Thanks, >>> >>> -- >>> 河野 達也 >>> Tatsuya Kawano (Mr.) >>> Tokyo, Japan >>> >>> twitter: http://twitter.com/tatsuya6502