// CAS does an atomic compare-and-swap on a counter. func (Example) CAS(c context.Context, r *CASReq) (err error) { success := false c = prod.Use(c) err = rdsS.Get(c).RunInTransaction(func(c context.Context) error { rds := rdsS.Get(c) key := rds.NewKey("Counter", r.Name, 0, nil) ctr := &Counter{} pls := rdsS.GetPLS(ctr) if err := rds.Get(key, pls); err != nil { return err } if ctr.Val == r.OldVal { success = true ctr.Val = r.NewVal _, err := rds.Put(key, pls) return err } success = false return nil }, nil) if err == nil && !success { err = endpoints.ConflictError } return }
func TestGetEntityGroupVersion(t *testing.T) { t.Parallel() Convey("GetEntityGroupVersion", t, func() { c := memory.Use(context.Background()) c, fb := featureBreaker.FilterRDS(c, errors.New("INTERNAL_ERROR")) rds := rawdatastore.Get(c) aKey, err := rds.Put(rds.NewKey("A", "", 0, nil), rawdatastore.PropertyMap{ "Val": {rawdatastore.MkProperty(10)}, }) So(err, ShouldBeNil) v, err := GetEntityGroupVersion(c, aKey) So(err, ShouldBeNil) So(v, ShouldEqual, 1) So(rds.Delete(aKey), ShouldBeNil) v, err = GetEntityGroupVersion(c, rds.NewKey("madeUp", "thing", 0, aKey)) So(err, ShouldBeNil) So(v, ShouldEqual, 2) v, err = GetEntityGroupVersion(c, rds.NewKey("madeUp", "thing", 0, nil)) So(err, ShouldBeNil) So(v, ShouldEqual, 0) fb.BreakFeatures(nil, "Get") v, err = GetEntityGroupVersion(c, aKey) So(err.Error(), ShouldContainSubstring, "INTERNAL_ERROR") }) }
// Add adds a value to the current counter, and returns the old+new values. It // may cause a counter to come into existance. func (Example) Add(c context.Context, r *AddReq) (rsp *AddRsp, err error) { rsp = &AddRsp{} c = prod.Use(c) err = rdsS.Get(c).RunInTransaction(func(c context.Context) error { rds := rdsS.Get(c) ctr := &Counter{} pls := rdsS.GetPLS(ctr) key := rds.NewKey("Counter", r.Name, 0, nil) if err := rds.Get(key, pls); err != nil && err != rdsS.ErrNoSuchEntity { return err } rsp.Prev = ctr.Val ctr.Val += r.Delta rsp.Cur = ctr.Val _, err := rds.Put(key, pls) return err }, nil) return }
// CurrentValue gets the current value of a counter (duh) func (Example) CurrentValue(c context.Context, r *CurrentValueReq) (rsp *CurrentValueRsp, err error) { c = prod.Use(c) rds := rdsS.Get(c) key := rds.NewKey("Counter", r.Name, 0, nil) ctr := &Counter{} if err = rds.Get(key, rdsS.GetPLS(ctr)); err != nil { return } rsp = &CurrentValueRsp{ctr.Val} return }
// GetEntityGroupVersion returns the entity group version for the entity group // containing root. If the entity group doesn't exist, this function will return // zero and a nil error. func GetEntityGroupVersion(c context.Context, root rdsS.Key) (int64, error) { for root.Parent() != nil { root = root.Parent() } rds := rdsS.Get(c) egm := &EntityGroupMeta{} err := rds.Get(rds.NewKey("__entity_group__", "", 1, root), rdsS.GetPLS(egm)) ret := egm.Version if err == rdsS.ErrNoSuchEntity { // this is OK for callers. The version of the entity group is effectively 0 // in this case. err = nil } return ret, err }
// List returns a list of all the counters. Note that it's very poorly // implemented! It's completely unpaged. I don't care :). func (Example) List(c context.Context) (rsp *ListRsp, err error) { rds := rawdatastore.Get(prod.Use(c)) rsp = &ListRsp{} dst := []rawdatastore.PropertyMap{} _, err = rds.GetAll(rds.NewQuery("Counter"), &dst) if err != nil { return } rsp.Counters = make([]Counter, len(dst)) for i, m := range dst { if err = rawdatastore.GetPLS(rsp.Counters[i]).Load(m); err != nil { return } } return }