views:

528

answers:

1

I'm trying to port the Sharding Counters example (code.google.com/appengine/articles/sharding_counters.html) to Java. The only problem is that the Java API does not have a call similar to Python's 'get_by_key_name'. This is the basic idea:

            Transaction tx = pm.currentTransaction();
            Key key = KeyFactory.createKey(CounterShard.class.getSimpleName(), counter + randomIndex);
            CounterShard shard = pm.getObjectById(CounterShard.class, key);
            if (shard == null) {  // API does not work this way...
                shard = new CounterShard(key, counter);
            }
            shard.increment();
            pm.makePersistent(shard);
            tx.commit();

Unfortunately, this throws a JDOObjectNotFoundException the first time I run it. I could run a query to determine if a counter for a given name exists, but that is not transactional. Another thread could do the same and in the end both would create an object with the same key.

From what I understand, the only operations supported within a transaction (for the Java API) are get and put. So how can I lock an object by key that does not exist yet (i.e. no 'get') and make sure that I am the first and only one creating it?

+2  A: 

check the demo code here

http://code.google.com/p/googleappengine/source/browse/trunk/java/demos/shardedcounter/README

Chii
Thanks for pointing out the example. I took a close look, but came to the conclusion that the Java example is not transactional either, i.e. there is a chance that a shard is incremented before it is created. Take a look at ShardedCounter.increment(int). It queries for a shard with a given index and only if it could find it increments it. If it could not find it, it just drops it. It also does not seem to use any transaction or locking mechanism. What if a shard is updated concurrently? I must be missing something...