Jan Vladimir Mostert
Jan Vladimir Mostert

Reputation: 12972

Using Objectify to concurrently write data on GAE

Let's for example say I have the following objectify model:

@Cache
@Entity
public class CompanyViews implements Serializable, Persistence {

    @Id
    private Long id;
    private Date created;
    private Date modified;
    private Long companyId;

    ........

    private Integer counter;

    ........

    @Override
    public void persist() {
        persist(false);
    }

    @Override
    public void persist(Boolean async) {
        ObjectifyService.register(Feedback.class);
        // setup some variables
        setUuid(UUID.randomUUID().toString().toUpperCase());
        setModified(new Date());
        if (getCreated() == null) {
            setCreated(new Date());
        }   
        // do the persist
        if (async) {
            ofy().save().entity(this);
        } else {
            ofy().save().entity(this).now();
        }           
    }
}

I want to use the counter field to track the number of views, or number opens or basically count something using an integer field.

What happens now is that for one GAE instance, the following will be called:

A:

CompanyViews views = CompanyViews.findByCompanyId(...);
views.setCounter(views.getCounter() + 1);
views.persist();

and for another instance:

B:

CompanyViews views = CompanyViews.findByCompanyId(...);
views.setCounter(views.getCounter() + 1);
views.persist();

If they both read the counter at the same time or read the counter before the other instance has persisted it, they will overwrite each other.

In MySQL / Postgres you get row-level locking, how does one do a "row-level lock" for Objectify entities on GAE?

Upvotes: 1

Views: 581

Answers (1)

Peter Knego
Peter Knego

Reputation: 80340

You need to use transactions when concurrently updating entities.

Note that since you update same entity you will have a limitation of about 1 write/s. To work around that look into sharding counters.

Upvotes: 1

Related Questions