func (this *FunServantImpl) CbAdd(ctx *rpc.Context, bucket string, key string, val []byte, expire int32) (r bool, ex error) { const IDENT = "cb.add" if this.cb == nil { ex = ErrServantNotStarted return } profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) b, err := this.cb.GetBucket(bucket) if err != nil { ex = err return } r, ex = b.AddRaw(key, int(expire), val) if ex != nil { log.Error("Q=%s %s: %s %s", IDENT, ctx.String(), key, ex) } profiler.do(IDENT, ctx, "{b^%s k^%s v^%s exp^%d} {r^%v}", bucket, key, string(val), expire, r) return }
// append raw data to an existing item func (this *FunServantImpl) CbAppend(ctx *rpc.Context, bucket string, key string, val []byte) (ex error) { const IDENT = "cb.append" if this.cb == nil { ex = ErrServantNotStarted return } profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) b, err := this.cb.GetBucket(bucket) if err != nil { ex = err return } ex = b.Append(key, val) if ex != nil { log.Error("Q=%s %s: %s %s", IDENT, ctx.String(), key, ex) } profiler.do(IDENT, ctx, "{b^%s k^%s v^%s}", bucket, key, string(val)) return }
func (this *FunServantImpl) McIncrement(ctx *rpc.Context, pool string, key string, delta int64) (r int64, ex error) { const IDENT = "mc.inc" if this.mc == nil { ex = ErrServantNotStarted return } svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } newVal, err := this.mc.Increment(pool, key, delta) if err == nil { r = int64(newVal) } else if err != memcache.ErrCacheMiss { log.Error("Q=%s %s {key^%s}: %v", IDENT, ctx.String(), key, err) } profiler.do(IDENT, ctx, "{key^%s delta^%d} {err^%v r^%d}", key, delta, ex, r) return }
func (this *FunServantImpl) Lock(ctx *rpc.Context, reason string, key string) (r bool, ex error) { const IDENT = "lock" svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } var peer string if ctx.IsSetSticky() && *ctx.Sticky { svtStats.incPeerCall() r = this.lk.Lock(key) } else { svt, err := this.proxy.ServantByKey(key) // FIXME add prefix? if err != nil { ex = err if svt != nil { if proxy.IsIoError(err) { svt.Close() } svt.Recycle() } return } if svt == proxy.Self { r = this.lk.Lock(key) } else { svtStats.incCallPeer() peer = svt.Addr() svt.HijackContext(ctx) r, ex = svt.Lock(ctx, reason, key) if ex != nil { if proxy.IsIoError(ex) { svt.Close() } } svt.Recycle() } } profiler.do(IDENT, ctx, "P=%s {reason^%s key^%s} {r^%v}", peer, reason, key, r) if !r { log.Warn("P=%s lock failed: {reason^%s key^%s}", peer, reason, key) } return }
func (this *FunServantImpl) Unlock(ctx *rpc.Context, reason string, key string) (ex error) { const IDENT = "unlock" svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } var peer string if ctx.IsSetSticky() && *ctx.Sticky { svtStats.incPeerCall() this.lk.Unlock(key) } else { svt, err := this.proxy.ServantByKey(key) if err != nil { ex = err if svt != nil { if proxy.IsIoError(err) { svt.Close() } svt.Recycle() } return } if svt == proxy.Self { this.lk.Unlock(key) } else { svtStats.incCallPeer() peer = svt.Addr() svt.HijackContext(ctx) ex = svt.Unlock(ctx, reason, key) if ex != nil { if proxy.IsIoError(ex) { svt.Close() } } svt.Recycle() } } profiler.do(IDENT, ctx, "P=%s {reason^%s key^%s}", peer, reason, key) return }
func (this *FunServantImpl) MyEvict(ctx *rpc.Context, cacheKey string) (ex error) { const IDENT = "my.evict" svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } var peer string if ctx.IsSetSticky() && *ctx.Sticky { svtStats.incPeerCall() this.dbCacheStore.Del(cacheKey) } else { svt, err := this.proxy.ServantByKey(cacheKey) if err != nil { ex = err if svt != nil { if proxy.IsIoError(err) { svt.Close() } svt.Recycle() } return } if svt == proxy.Self { this.dbCacheStore.Del(cacheKey) } else { svtStats.incCallPeer() peer = svt.Addr() svt.HijackContext(ctx) ex = svt.MyEvict(ctx, cacheKey) if ex != nil { if proxy.IsIoError(ex) { svt.Close() } } svt.Recycle() } } profiler.do(IDENT, ctx, "{key^%s} {p^%s}", cacheKey, peer) return }
func (this *FunServantImpl) CbGet(ctx *rpc.Context, bucket string, key string) (r *rpc.TCouchbaseData, ex error) { const IDENT = "cb.get" if this.cb == nil { ex = ErrServantNotStarted return } profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) b, err := this.cb.GetBucket(bucket) if err != nil { ex = err return } r = rpc.NewTCouchbaseData() var data []byte data, ex = b.GetRaw(key) if ex != nil { r.Missed = true if e, ok := ex.(*gomemcached.MCResponse); ok && e.Status == gomemcached.KEY_ENOENT { ex = nil } else { log.Error("Q=%s %s %s: %s", IDENT, ctx.String(), key, ex.Error()) } } else { r.Data = data r.Missed = false } profiler.do(IDENT, ctx, "{b^%s k^%s} {r^%s}", bucket, key, string(r.Data)) return }
func (this *FunServantImpl) Ping(ctx *rpc.Context) (r string, ex error) { const IDENT = "ping" profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) r = fmt.Sprintf("ver:%s, build:%s, myid:%d, uptime:%s", server.Version, server.BuildId, this.conf.IdgenWorkerId, time.Since(this.startedAt)) profiler.do(IDENT, ctx, "ctx^%s {r^%s}", ctx.String(), r) return }
func (this *FunServantImpl) CbDel(ctx *rpc.Context, bucket string, key string) (r bool, ex error) { const IDENT = "cb.del" if this.cb == nil { ex = ErrServantNotStarted return } profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) b, err := this.cb.GetBucket(bucket) if err != nil { ex = err return } ex = b.Delete(key) if ex != nil { r = false if e, ok := ex.(*gomemcached.MCResponse); ok && e.Status == gomemcached.KEY_ENOENT { ex = nil } else { // unexpected err log.Error("Q=%s %s %s: %s", IDENT, ctx.String(), key, ex.Error()) } } else { // found this item, and deleted successfully r = true } profiler.do(IDENT, ctx, "{b^%s k^%s} {r^%v}", bucket, key, r) return }
func (this *FunServantImpl) McAdd(ctx *rpc.Context, pool string, key string, value *rpc.TMemcacheData, expiration int32) (r bool, ex error) { const IDENT = "mc.add" if this.mc == nil { ex = ErrServantNotStarted return } svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } ex = this.mc.Add(pool, &memcache.Item{Key: key, Value: value.Data, Flags: uint32(value.Flags), Expiration: expiration}) if ex == nil { r = true } else { if ex == memcache.ErrNotStored { ex = nil } else { log.Error("Q=%s %s {key^%s}: %v", IDENT, ctx.String(), key, ex) } } profiler.do(IDENT, ctx, "{key^%s val^%s exp^%d} {err^%v r^%v}", key, value, expiration, ex, r) return }
func (this *FunServantImpl) McGet(ctx *rpc.Context, pool string, key string) (r *rpc.TMemcacheData, miss *rpc.TCacheMissed, ex error) { const IDENT = "mc.get" if this.mc == nil { ex = ErrServantNotStarted return } svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } it, err := this.mc.Get(pool, key) if err == nil { // cache hit r = rpc.NewTMemcacheData() r.Data = it.Value r.Flags = int32(it.Flags) } else if err == memcache.ErrCacheMiss { // cache miss miss = rpc.NewTCacheMissed() miss.Message = thrift.StringPtr(err.Error()) // optional } else { ex = err log.Error("Q=%s %s {key^%s}: %v", IDENT, ctx.String(), key, err) } profiler.do(IDENT, ctx, "{key^%s} {miss^%v val^%s}", key, miss, r) return }
// fetches multiple keys concurrently func (this *FunServantImpl) CbGets(ctx *rpc.Context, bucket string, keys []string) (r map[string][]byte, ex error) { const IDENT = "cb.gets" if this.cb == nil { ex = ErrServantNotStarted return } profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) b, err := this.cb.GetBucket(bucket) if err != nil { ex = err return } var rv map[string]*gomemcached.MCResponse rv, ex = b.GetBulk(keys) r = make(map[string][]byte) if ex != nil { log.Error("Q=%s %s: %v %s", IDENT, ctx.String(), keys, ex) } else { for k, data := range rv { r[k] = data.Body } } profiler.do(IDENT, ctx, "{b^%s k^%v} {r^%d}", bucket, keys, len(r)) return }
func (this *FunServantImpl) McDelete(ctx *rpc.Context, pool string, key string) (r bool, ex error) { const IDENT = "mc.del" if this.mc == nil { ex = ErrServantNotStarted return } svtStats.inc(IDENT) profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } ex = this.mc.Delete(pool, key) if ex == nil { r = true } else { if ex == memcache.ErrCacheMiss { ex = nil } else { log.Error("Q=%s %s {key^%s}: %v", IDENT, ctx.String(), key, ex) } } profiler.do(IDENT, ctx, "{key^%s} {err^%v r^%v}", key, ex, r) return }
func (this *FunServantImpl) MyQuery(ctx *rpc.Context, pool string, table string, hintId int64, sql string, args []string, cacheKey string) (r *rpc.MysqlResult, ex error) { const IDENT = "my.query" profiler, err := this.getSession(ctx).startProfiler() if err != nil { ex = err return } svtStats.inc(IDENT) var ( cacheKeyHash = cacheKey peer string rows int ) if cacheKey != "" && this.conf.Mysql.CacheKeyHash { hashSum := sha1.Sum([]byte(cacheKey)) // sha1.Size cacheKeyHash = string(hashSum[:]) } if cacheKeyHash == "" { r, ex = this.doMyQuery(IDENT, ctx, pool, table, hintId, sql, args, cacheKeyHash) rows = len(r.Rows) if r.RowsAffected > 0 { rows = int(r.RowsAffected) } } else { if ctx.IsSetSticky() && *ctx.Sticky { svtStats.incPeerCall() r, ex = this.doMyQuery(IDENT, ctx, pool, table, hintId, sql, args, cacheKeyHash) rows = len(r.Rows) if r.RowsAffected > 0 { rows = int(r.RowsAffected) } } else { svt, err := this.proxy.ServantByKey(cacheKey) if err != nil { ex = err if svt != nil { if proxy.IsIoError(err) { svt.Close() } svt.Recycle() } return } if svt == proxy.Self { r, ex = this.doMyQuery(IDENT, ctx, pool, table, hintId, sql, args, cacheKeyHash) rows = len(r.Rows) if r.RowsAffected > 0 { rows = int(r.RowsAffected) } } else { // dispatch to peer svtStats.incCallPeer() peer = svt.Addr() svt.HijackContext(ctx) r, ex = svt.MyQuery(ctx, pool, table, hintId, sql, args, cacheKey) if ex != nil { if proxy.IsIoError(ex) { svt.Close() } } else { rows = len(r.Rows) if r.RowsAffected > 0 { rows = int(r.RowsAffected) } } svt.Recycle() // NEVER forget about this } } } if ex != nil { profiler.do(IDENT, ctx, "P=%s {cache^%s pool^%s table^%s id^%d sql^%s args^%+v} {err^%s}", peer, cacheKey, pool, table, hintId, sql, args, ex) } else { profiler.do(IDENT, ctx, "P=%s {cache^%s pool^%s table^%s id^%d sql^%s args^%+v} {rows^%d r^%+v}", peer, cacheKey, pool, table, hintId, sql, args, rows, *r) } return }
// append my transaction id and my host ip to ctx func (this *FunServantPeer) HijackContext(ctx *rpc.Context) { ctx.Sticky = new(bool) *ctx.Sticky = true // tells peer it's from fae }