예제 #1
0
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
}
예제 #2
0
파일: table.go 프로젝트: tradia/gotable
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)
}
예제 #3
0
func TestTableZScan(t *testing.T) {
	// MZSET
	{
		var in proto.PkgMultiOp
		in.Cmd = proto.CmdMSet
		in.DbId = 2
		in.Seq = 20
		in.PkgFlag |= proto.FlagZop
		in.Kvs = append(in.Kvs, getTestKV(2, []byte("row2"), []byte("col0"), []byte("v0"), 40, 0))
		in.Kvs = append(in.Kvs, getTestKV(2, []byte("row2"), []byte("col1"), []byte("v1"), 30, 0))
		in.Kvs = append(in.Kvs, getTestKV(2, []byte("row2"), []byte("col2"), []byte("v2"), 20, 0))
		in.Kvs = append(in.Kvs, getTestKV(2, []byte("row2"), []byte("col3"), []byte("v3"), 10, 0))
		in.Kvs = append(in.Kvs, getTestKV(2, []byte("row2"), []byte("col4"), []byte("v4"), 0, 0))

		myMSet(in, testAuth, getTestWA(), true, t)
	}

	// ZSCAN ASC order by SCORE
	var in proto.PkgScanReq
	in.Cmd = proto.CmdScan
	in.DbId = 2
	in.Seq = 20
	in.Num = 10
	in.TableId = 2
	in.RowKey = []byte("row2")
	in.SetScore(-1)
	in.ColKey = []byte("")
	in.PkgFlag |= proto.FlagScanAsc
	in.SetColSpace(proto.ColSpaceScore1) // order by SCORE

	out := myScan(in, testAuth, t)
	if len(out.Kvs) != 5 {
		t.Fatalf("Invalid KV number: %d", len(out.Kvs))
	}
	if out.PkgFlag&proto.FlagScanEnd == 0 {
		t.Fatalf("Scan should end")
	}
	for i := 0; i < len(out.Kvs); i++ {
		idx := 4 - i
		if out.Kvs[i].ErrCode != 0 {
			t.Fatalf("ErrCode is 0")
		}
		if out.Kvs[i].TableId != 2 {
			t.Fatalf("TableId mismatch")
		}
		if bytes.Compare(out.Kvs[i].RowKey, []byte("row2")) != 0 {
			t.Fatalf("RowKey mismatch")
		}
		if bytes.Compare(out.Kvs[i].ColKey, []byte(fmt.Sprintf("col%d", idx))) != 0 {
			t.Fatalf("ColKey mismatch")
		}
		if out.Kvs[i].Score != int64(i*10) {
			t.Fatalf("Score mismatch")
		}
		if bytes.Compare(out.Kvs[i].Value, []byte(fmt.Sprintf("v%d", idx))) != 0 {
			t.Fatalf("Value mismatch")
		}
	}

	// ZSCAN DESC order by SCORE
	in.PkgFlag &^= 0xFF
	in.PkgFlag |= proto.FlagScanKeyStart

	out = myScan(in, testAuth, t)
	if len(out.Kvs) != 5 {
		t.Fatalf("Invalid KV number: %d", len(out.Kvs))
	}
	if out.PkgFlag&proto.FlagScanEnd == 0 {
		t.Fatalf("Scan should end")
	}
	for i := 0; i < len(out.Kvs); i++ {
		idx := 4 - i
		if out.Kvs[i].ErrCode != 0 {
			t.Fatalf("ErrCode is 0")
		}
		if out.Kvs[i].TableId != 2 {
			t.Fatalf("TableId mismatch")
		}
		if bytes.Compare(out.Kvs[i].RowKey, []byte("row2")) != 0 {
			t.Fatalf("RowKey mismatch")
		}
		if bytes.Compare(out.Kvs[i].ColKey, []byte(fmt.Sprintf("col%d", i))) != 0 {
			t.Fatalf("ColKey mismatch")
		}
		if out.Kvs[i].Score != int64(idx*10) {
			t.Fatalf("Score mismatch")
		}
		if bytes.Compare(out.Kvs[i].Value, []byte(fmt.Sprintf("v%d", i))) != 0 {
			t.Fatalf("Value mismatch")
		}
	}
}
예제 #4
0
파일: context.go 프로젝트: tradia/gotable
func (c *Context) goScan(zop bool, tableId uint8, rowKey, colKey []byte,
	score int64, start, asc, orderByScore bool, num int,
	done chan *Call) (*Call, error) {
	call := c.cli.newCall(proto.CmdScan, done)
	if call.err != nil {
		return call, call.err
	}

	if num < 1 {
		c.cli.errCall(call, ErrInvScanNum)
		return call, call.err
	}

	var p proto.PkgScanReq
	p.Seq = call.seq
	p.DbId = c.dbId
	p.Cmd = call.cmd
	if asc {
		p.PkgFlag |= proto.FlagScanAsc
	}
	if start {
		p.PkgFlag |= proto.FlagScanKeyStart
	}
	p.Num = uint16(num)
	p.TableId = tableId
	p.RowKey = rowKey
	p.ColKey = colKey

	// ZScan
	if zop {
		p.PkgFlag |= proto.FlagZop
		p.SetScore(score)
		if orderByScore {
			p.SetColSpace(proto.ColSpaceScore1)
		} else {
			p.SetColSpace(proto.ColSpaceScore2)
		}
	}

	var pkgLen = p.Length()
	if pkgLen > proto.MaxPkgLen {
		c.cli.errCall(call, ErrInvPkgLen)
		return call, call.err
	}

	call.pkg = make([]byte, pkgLen)
	_, err := p.Encode(call.pkg)
	if err != nil {
		c.cli.errCall(call, err)
		return call, err
	}

	call.ctx = scanContext{tableId, rowKey, zop, asc, orderByScore, num}
	c.cli.sending <- call

	return call, nil
}