0

I wonder if my case is consistency issue...

I have an entity class Player, which has a field lastAttackDate. I set lastAttackDate = sysdate in a transaction, then I commit that transaction, and then I query for players with lastAttackDate < sysdate - 10min (please see the simplified code).

private static final Logger log = Logger.getLogger(MyEndpoint.class.getName());
@ApiMethod(name = "attack")
public MyResult attack(@Named("id") Long id, User user) throws Exception, OAuthRequestException, IOException {
    PersistenceManager mgr = null;
    Player defender = null;
    Transaction tx = null;
    try {
        mgr = getPersistenceManager();
        tx = mgr.currentTransaction();
        tx.begin();
        long now = new Date().getTime();
        defender = getPlayer(mgr, id);//I get player by param ID
        defender.setLastAttackDate(now);
        tx.commit();           //mgr.close(); mgr = getPersistenceManager();--> I tried that, it did not help
        long param = now - 10*60*1000;//sysdate - 10 minutes
        Query q = pm.newQuery("select from " + Player.class.getName() +" where lastAttackDate  < lastAttackDateParam parameters long lastAttackDateParam");
        Set<Player> result = new HashSet<Player>();
        result.addAll((List<Player>) q.execute(param));
        Iterator<Player> it = results.iterator();
        while(it.hasNext())
          {
           Player p = it.next();
           if (p.getLastAttackDate() >= param)
           {
           log.log(Level.SEVERE, "It really just gave me a result that doesn't meet the criteria");//defender (the recently updated player) falls in this category
           it.remove();
           }
        }
    }
    finally {
        if (tx != null && tx.isActive())
            tx.rollback();
        if (mgr != null)
            mgr.close();
        return null;
        }
}

What bothers me is that this query still gives me defender as a result. What bothers me even more, is that if I iterate through result and I check if it meets the criteria, I can see that it does not. If it was consistency issue, I'd suspect that getLastAttackDate() should return old, not updated value, but it gives the right one, the most recent one. What do I do wrong? What can I do to make it work?

At the moment, I iterate through the result set and remove the entries that do not meet my search criteria, but it is expensive (reads, cpu time, possibly additional query to try again).

Dan McGrath
  • 41,220
  • 11
  • 99
  • 130
user2855896
  • 270
  • 2
  • 11
  • The code you show seems a bit too little -- I don't see what you had set `name` to, nor what `name` do you see in the query's return. Perhaps expand a bit and show some results too? – Alex Martelli Jan 02 '15 at 15:34
  • 1
    Anyway, if an eventual-consistency issue does emerge, and you require strong-consistency here, maybe an ancestor query can help: see https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/ and https://cloud.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency (the latter's for Python but the underlying datastore is the same for any language you use). – Alex Martelli Jan 02 '15 at 15:37
  • @AlexMartelli Thanks for your input. I used this name for example to simplify it, but I guess it made the example harder instead.. I edited my post, more code now and the "name" is gone. Please re-read the question. I don't think I can use ancestors. In my case, each player can interact (attack) with any other player, and I query through all the players to get those that were not "attacked" in last 10 minutes – user2855896 Jan 02 '15 at 16:07
  • Unfortunately I'm no expert in the Java layer(s) on top of the datastore so I can't tell exactly what's going on, but I'm still slightly confused at the example. You look for players such that `lastAttackDate < lastAttackDateParam` but then log as a severe error `if (p.getLastAttackDate() <= param)` which is exactly the condition you just queried for. Some typo maybe, or am I missing something? Anyway, of course you can use ancestors if you wish: just make all players descendant of a single entity `x` and query that way. Maybe no improvement but you'll know if consistency is the problem! – Alex Martelli Jan 02 '15 at 17:03
  • Thanks again for checking my topic. Indeed a typo here in simplified example... I search for players that lastAttackDate < param, and then log if lastAttackDate >= param. I read your links and I think my problem is "Eventual Consistency on Reading an Index". Sure, I can make all players descendant of a single entity just to check if it solves the problem, but I can't use that solution as I would limit myself to 1 update on players per second. Anyway, I think my problem is indeed consistency issue, and I think best I can do is to check it twice & remove (I updated the code to show my solution) – user2855896 Jan 02 '15 at 18:39

0 Answers0