func incr(c appengine.Context, key string, delta int64, initialValue *uint64) (newValue uint64, err error) { req := &pb.MemcacheIncrementRequest{ Key: []byte(key), InitialValue: initialValue, } if delta >= 0 { req.Delta = proto.Uint64(uint64(delta)) } else { req.Delta = proto.Uint64(uint64(-delta)) req.Direction = pb.MemcacheIncrementRequest_DECREMENT.Enum() } res := &pb.MemcacheIncrementResponse{} err = c.Call("memcache", "Increment", req, res, nil) if err != nil { return } if res.NewValue == nil { return 0, ErrCacheMiss } return *res.NewValue, nil }
// set sets the given items using the given conflict resolution policy. // appengine.MultiError may be returned. func set(c appengine.Context, item []*Item, value [][]byte, policy pb.MemcacheSetRequest_SetPolicy) error { req := &pb.MemcacheSetRequest{ Item: make([]*pb.MemcacheSetRequest_Item, len(item)), } for i, t := range item { p := &pb.MemcacheSetRequest_Item{ Key: []byte(t.Key), } if value == nil { p.Value = t.Value } else { p.Value = value[i] } if t.Flags != 0 { p.Flags = proto.Uint32(t.Flags) } if t.Expiration != 0 { // In the .proto file, MemcacheSetRequest_Item uses a fixed32 (i.e. unsigned) // for expiration time, while MemcacheGetRequest_Item uses int32 (i.e. signed). // Throughout this .go file, we use int32. // Also, in the proto, the expiration value is either a duration (in seconds) // or an absolute Unix timestamp (in seconds), depending on whether the // value is less than or greater than or equal to 30 years, respectively. if t.Expiration < time.Second { // Because an Expiration of 0 means no expiration, we take // care here to translate an item with an expiration // Duration between 0-1 seconds as immediately expiring // (saying it expired a few seconds ago), rather than // rounding it down to 0 and making it live forever. p.ExpirationTime = proto.Uint32(uint32(time.Now().Unix()) - 5) } else if t.Expiration >= thirtyYears { p.ExpirationTime = proto.Uint32(uint32(time.Now().Unix()) + uint32(t.Expiration/time.Second)) } else { p.ExpirationTime = proto.Uint32(uint32(t.Expiration / time.Second)) } } if t.casID != 0 { p.CasId = proto.Uint64(t.casID) p.ForCas = proto.Bool(true) } p.SetPolicy = policy.Enum() req.Item[i] = p } res := &pb.MemcacheSetResponse{} if err := c.Call("memcache", "Set", req, res, nil); err != nil { return err } if len(res.SetStatus) != len(item) { return ErrServerError } me, any := make(appengine.MultiError, len(item)), false for i, st := range res.SetStatus { var err error switch st { case pb.MemcacheSetResponse_STORED: // OK case pb.MemcacheSetResponse_NOT_STORED: err = ErrNotStored case pb.MemcacheSetResponse_EXISTS: err = ErrCASConflict default: err = ErrServerError } if err != nil { me[i] = err any = true } } if any { return me } return nil }