func myScan(in proto.PkgScanReq, au Authorize, t *testing.T) proto.PkgScanResp { var pkg = make([]byte, in.Length()) _, err := in.Encode(pkg) if err != nil { t.Fatalf("Encode failed: ", err) } pkg = testTbl.Scan(&PkgArgs{in.Cmd, in.DbId, in.Seq, pkg}, au) var out proto.PkgScanResp _, err = out.Decode(pkg) if err != nil { t.Fatalf("Decode failed: ", err) } if out.ErrCode != 0 { t.Fatalf("Failed with ErrCode %d", out.ErrCode) } if out.DbId != in.DbId || out.Seq != in.Seq { t.Fatalf("DbId/Seq mismatch") } return out }
func (tbl *Table) Scan(req *PkgArgs, au Authorize) []byte { var out proto.PkgScanResp out.Cmd = req.Cmd out.DbId = req.DbId out.Seq = req.Seq var in proto.PkgScanReq n, err := in.Decode(req.Pkg) if err != nil || n != len(req.Pkg) { return errorHandle(&out, table.EcDecodeFail) } out.PkgFlag = in.PkgFlag if in.DbId == proto.AdminDbId { return errorHandle(&out, table.EcInvDbId) } if !au.IsAuth(in.DbId) { return errorHandle(&out, table.EcNoPrivilege) } if in.ColSpace == proto.ColSpaceScore1 { tbl.zScanSortScore(&in, &out) return replyHandle(&out) } var scanColSpace uint8 = proto.ColSpaceDefault if in.ColSpace == proto.ColSpaceScore2 { scanColSpace = proto.ColSpaceScore2 } var it = tbl.db.NewIterator(nil) defer it.Destroy() var scanAsc = (in.PkgFlag&proto.FlagScanAsc != 0) var startSeek = (in.PkgFlag&proto.FlagScanKeyStart != 0) if scanAsc { if startSeek { // Seek to the first element it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, nil)) } else { it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, in.ColKey)) } } else { if startSeek { // Seek to the last element it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace+1, in.RowKey, nil)) } else { it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, in.ColKey)) } if !it.Valid() { it.SeekToLast() } } out.PkgFlag |= proto.FlagScanEnd var first = true var scanNum = int(in.Num) var pkgLen = proto.HeadSize + 1000 for i := 0; it.Valid() && i < scanNum+1; iterMove(it, scanAsc) { _, dbId, tableId, colSpace, rowKey, colKey := parseRawKey(it.Key()) if dbId != in.DbId || tableId != in.TableId || colSpace != scanColSpace || bytes.Compare(rowKey, in.RowKey) != 0 { if first { first = false continue } else { break } } if first { first = false } if !startSeek { if scanAsc { if bytes.Compare(colKey, in.ColKey) <= 0 { continue } } else { if bytes.Compare(colKey, in.ColKey) >= 0 { continue } } } if i < scanNum { var kv proto.KeyValue kv.TableId = in.TableId kv.RowKey = in.RowKey kv.ColKey = colKey kv.Value, kv.Score = parseRawValue(it.Value()) if len(kv.Value) > 0 { kv.CtrlFlag |= proto.CtrlValue } if kv.Score != 0 { kv.CtrlFlag |= proto.CtrlScore } out.Kvs = append(out.Kvs, kv) pkgLen += kv.Length() if pkgLen > proto.MaxPkgLen/2 { out.PkgFlag &^= proto.FlagScanEnd break } } else { out.PkgFlag &^= proto.FlagScanEnd break } i++ } return replyHandle(&out) }
func (tbl *Table) zScanSortScore(in *proto.PkgScanReq, out *proto.PkgScanResp) { var it = tbl.db.NewIterator(nil) defer it.Destroy() var scanAsc = (in.PkgFlag&proto.FlagScanAsc != 0) var startSeek = (in.PkgFlag&proto.FlagScanKeyStart != 0) var scanColSpace uint8 = proto.ColSpaceScore1 if scanAsc { if startSeek { // Seek to the first element it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, nil)) } else { it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, newScoreColKey(in.Score, in.ColKey))) } } else { if startSeek { // Seek to the last element it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace+1, in.RowKey, nil)) } else { it.Seek(getRawKey(in.DbId, in.TableId, scanColSpace, in.RowKey, newScoreColKey(in.Score, in.ColKey))) } if !it.Valid() { it.SeekToLast() } } out.PkgFlag |= proto.FlagScanEnd var first = true var scanNum = int(in.Num) var pkgLen = proto.HeadSize + 1000 for i := 0; it.Valid() && i < scanNum+1; iterMove(it, scanAsc) { _, dbId, tableId, colSpace, rowKey, colKey := parseRawKey(it.Key()) if dbId != in.DbId || tableId != in.TableId || colSpace != scanColSpace || bytes.Compare(rowKey, in.RowKey) != 0 { if first { first = false continue } else { break } } if first { first = false } if len(colKey) < 8 { continue // skip invalid record } zColKey, zScore := parseZColKey(colKey) if !startSeek { if scanAsc { if zScore < in.Score { continue } if zScore == in.Score && bytes.Compare(zColKey, in.ColKey) <= 0 { continue } } else { if zScore > in.Score { continue } if zScore == in.Score && bytes.Compare(zColKey, in.ColKey) >= 0 { continue } } } if i < scanNum { var kv proto.KeyValue kv.TableId = in.TableId kv.RowKey = in.RowKey kv.ColKey = zColKey kv.Value, _ = parseRawValue(it.Value()) kv.Score = zScore if len(kv.Value) > 0 { kv.CtrlFlag |= proto.CtrlValue } if kv.Score != 0 { kv.CtrlFlag |= proto.CtrlScore } out.Kvs = append(out.Kvs, kv) pkgLen += kv.Length() if pkgLen > proto.MaxPkgLen/2 { out.PkgFlag &^= proto.FlagScanEnd break } } else { out.PkgFlag &^= proto.FlagScanEnd break } i++ } }
// Get call reply. The real reply types are: // Auth/Ping/(Z)Set/(Z)Del: nil; // (Z)Get: GetReply; // (Z)Incr: IncrReply; // (Z)MGet: []GetReply; // (Z)MSet: []SetReply; // (Z)MDel: []DelReply; // (Z)MIncr: []IncrReply; // (Z)Scan: ScanReply; // Dump: DumpReply; func (call *Call) Reply() (interface{}, error) { if call.err != nil { return nil, call.err } if !call.ready { return nil, ErrCallNotReady } if proto.CmdAuth == call.cmd || proto.CmdPing == call.cmd || proto.CmdIncr == call.cmd || proto.CmdDel == call.cmd || proto.CmdSet == call.cmd || proto.CmdGet == call.cmd { var p proto.PkgOneOp _, err := p.Decode(call.pkg) if err != nil { call.err = err return nil, call.err } if p.ErrCode < 0 { return nil, getErr(p.ErrCode) } switch call.cmd { case proto.CmdAuth: return nil, nil case proto.CmdPing: return nil, nil case proto.CmdIncr: return IncrReply{p.ErrCode, p.TableId, copyBytes(p.RowKey), copyBytes(p.ColKey), copyBytes(p.Value), p.Score}, nil case proto.CmdDel: return nil, nil case proto.CmdSet: return nil, nil case proto.CmdGet: return GetReply{p.ErrCode, p.TableId, copyBytes(p.RowKey), copyBytes(p.ColKey), copyBytes(p.Value), p.Score, p.Cas}, nil } } if proto.CmdMIncr == call.cmd || proto.CmdMDel == call.cmd || proto.CmdMSet == call.cmd || proto.CmdMGet == call.cmd { var p proto.PkgMultiOp _, err := p.Decode(call.pkg) if err != nil { call.err = err return nil, call.err } if p.ErrCode < 0 { return nil, getErr(p.ErrCode) } switch call.cmd { case proto.CmdMIncr: var r = make([]IncrReply, len(p.Kvs)) for i := 0; i < len(r); i++ { r[i] = IncrReply{p.Kvs[i].ErrCode, p.Kvs[i].TableId, copyBytes(p.Kvs[i].RowKey), copyBytes(p.Kvs[i].ColKey), copyBytes(p.Kvs[i].Value), p.Kvs[i].Score} } return r, nil case proto.CmdMDel: var r = make([]DelReply, len(p.Kvs)) for i := 0; i < len(r); i++ { r[i] = DelReply{p.Kvs[i].ErrCode, p.Kvs[i].TableId, copyBytes(p.Kvs[i].RowKey), copyBytes(p.Kvs[i].ColKey)} } return r, nil case proto.CmdMSet: var r = make([]SetReply, len(p.Kvs)) for i := 0; i < len(r); i++ { r[i] = SetReply{p.Kvs[i].ErrCode, p.Kvs[i].TableId, copyBytes(p.Kvs[i].RowKey), copyBytes(p.Kvs[i].ColKey)} } return r, nil case proto.CmdMGet: var r = make([]GetReply, len(p.Kvs)) for i := 0; i < len(r); i++ { r[i] = GetReply{p.Kvs[i].ErrCode, p.Kvs[i].TableId, copyBytes(p.Kvs[i].RowKey), copyBytes(p.Kvs[i].ColKey), copyBytes(p.Kvs[i].Value), p.Kvs[i].Score, p.Kvs[i].Cas} } return r, nil } } switch call.cmd { case proto.CmdScan: var p proto.PkgScanResp _, err := p.Decode(call.pkg) if err != nil { call.err = err return nil, call.err } if p.ErrCode < 0 { return nil, getErr(p.ErrCode) } var r ScanReply r.ctx = call.ctx.(scanContext) r.TableId = r.ctx.tableId r.RowKey = r.ctx.rowKey r.End = (p.PkgFlag&proto.FlagScanEnd != 0) r.Kvs = make([]ScanKV, len(p.Kvs)) for i := 0; i < len(p.Kvs); i++ { r.Kvs[i] = ScanKV{copyBytes(p.Kvs[i].ColKey), copyBytes(p.Kvs[i].Value), p.Kvs[i].Score} } return r, nil case proto.CmdDump: var p proto.PkgDumpResp _, err := p.Decode(call.pkg) if err != nil { call.err = err return nil, call.err } if p.ErrCode < 0 { return nil, getErr(p.ErrCode) } var r DumpReply r.ctx = call.ctx.(dumpContext) r.ctx.lastSlotId = p.LastSlotId r.ctx.slotStart = (p.PkgFlag&proto.FlagDumpSlotStart != 0) r.End = (p.PkgFlag&proto.FlagDumpEnd != 0) r.Kvs = make([]DumpKV, len(p.Kvs)) for i := 0; i < len(p.Kvs); i++ { r.Kvs[i] = DumpKV{p.Kvs[i].TableId, p.Kvs[i].ColSpace, copyBytes(p.Kvs[i].RowKey), copyBytes(p.Kvs[i].ColKey), copyBytes(p.Kvs[i].Value), p.Kvs[i].Score} } return r, nil } switch call.cmd { case proto.CmdSlaveOf: return call.replyInnerCtrl(&ctrl.PkgSlaveOf{}) case proto.CmdMigrate: return call.replyInnerCtrl(&ctrl.PkgMigrate{}) case proto.CmdSlaveSt: return call.replyInnerCtrl(&ctrl.PkgSlaveStatus{}) case proto.CmdDelSlot: return call.replyInnerCtrl(&ctrl.PkgDelSlot{}) } return nil, ErrUnknownCmd }