2015-08-25 20:52:42 +02:00
|
|
|
// Copyright (c) 2015 Couchbase, Inc.
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
|
|
|
// except in compliance with the License. You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// Unless required by applicable law or agreed to in writing, software distributed under the
|
|
|
|
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
|
|
// either express or implied. See the License for the specific language governing permissions
|
|
|
|
// and limitations under the License.
|
|
|
|
|
|
|
|
package firestorm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
)
|
|
|
|
|
|
|
|
var StoredKeyPrefix = []byte{'s'}
|
|
|
|
|
|
|
|
type StoredRow struct {
|
|
|
|
docID []byte
|
|
|
|
docNum uint64
|
|
|
|
field uint16
|
|
|
|
arrayPositions []uint64
|
|
|
|
value StoredValue
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewStoredRow(docID []byte, docNum uint64, field uint16, arrayPositions []uint64, value []byte) *StoredRow {
|
|
|
|
rv := StoredRow{
|
|
|
|
docID: docID,
|
|
|
|
docNum: docNum,
|
|
|
|
field: field,
|
|
|
|
arrayPositions: arrayPositions,
|
|
|
|
}
|
|
|
|
if len(arrayPositions) < 1 {
|
|
|
|
rv.arrayPositions = make([]uint64, 0)
|
|
|
|
}
|
|
|
|
rv.value.Raw = value // FIXME review do we need to copy?
|
|
|
|
return &rv
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewStoredRowKV(key, value []byte) (*StoredRow, error) {
|
|
|
|
rv := StoredRow{}
|
2016-01-07 00:46:26 +01:00
|
|
|
err := rv.ParseKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = rv.value.Unmarshal(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &rv, nil
|
|
|
|
}
|
2015-08-25 20:52:42 +02:00
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
func (sr *StoredRow) ParseKey(key []byte) error {
|
2015-08-25 20:52:42 +02:00
|
|
|
buf := bytes.NewBuffer(key)
|
|
|
|
_, err := buf.ReadByte() // type
|
|
|
|
if err != nil {
|
2016-01-07 00:46:26 +01:00
|
|
|
return err
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
sr.docID, err = buf.ReadBytes(ByteSeparator)
|
|
|
|
if len(sr.docID) < 2 { // 1 for min doc id length, 1 for separator
|
2015-08-25 20:52:42 +02:00
|
|
|
err = fmt.Errorf("invalid doc length 0")
|
2016-01-07 00:46:26 +01:00
|
|
|
return err
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
sr.docID = sr.docID[:len(sr.docID)-1] // trim off separator byte
|
2015-08-25 20:52:42 +02:00
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
sr.docNum, err = binary.ReadUvarint(buf)
|
2015-08-25 20:52:42 +02:00
|
|
|
if err != nil {
|
2016-01-07 00:46:26 +01:00
|
|
|
return err
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
err = binary.Read(buf, binary.LittleEndian, &sr.field)
|
2015-08-25 20:52:42 +02:00
|
|
|
if err != nil {
|
2016-01-07 00:46:26 +01:00
|
|
|
return err
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
sr.arrayPositions = make([]uint64, 0)
|
2015-08-25 20:52:42 +02:00
|
|
|
nextArrayPos, err := binary.ReadUvarint(buf)
|
|
|
|
for err == nil {
|
2016-01-07 00:46:26 +01:00
|
|
|
sr.arrayPositions = append(sr.arrayPositions, nextArrayPos)
|
2015-08-25 20:52:42 +02:00
|
|
|
nextArrayPos, err = binary.ReadUvarint(buf)
|
|
|
|
}
|
|
|
|
|
2016-01-07 00:46:26 +01:00
|
|
|
return nil
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 16:26:01 +01:00
|
|
|
func (sr *StoredRow) KeySize() int {
|
|
|
|
return 1 + len(sr.docID) + 1 + binary.MaxVarintLen64 + 2 + (binary.MaxVarintLen64 * len(sr.arrayPositions))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) KeyTo(buf []byte) (int, error) {
|
2015-08-25 20:52:42 +02:00
|
|
|
buf[0] = 's'
|
|
|
|
copy(buf[1:], sr.docID)
|
2015-10-28 16:26:01 +01:00
|
|
|
buf[1+len(sr.docID)] = ByteSeparator
|
|
|
|
bytesUsed := 1 + len(sr.docID) + 1
|
2015-08-25 20:52:42 +02:00
|
|
|
bytesUsed += binary.PutUvarint(buf[bytesUsed:], sr.docNum)
|
|
|
|
binary.LittleEndian.PutUint16(buf[bytesUsed:], sr.field)
|
|
|
|
bytesUsed += 2
|
|
|
|
for _, arrayPosition := range sr.arrayPositions {
|
|
|
|
varbytes := binary.PutUvarint(buf[bytesUsed:], arrayPosition)
|
|
|
|
bytesUsed += varbytes
|
|
|
|
}
|
2015-10-28 16:26:01 +01:00
|
|
|
return bytesUsed, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) Key() []byte {
|
|
|
|
|
|
|
|
buf := make([]byte, sr.KeySize())
|
|
|
|
n, _ := sr.KeyTo(buf)
|
|
|
|
return buf[:n]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) ValueSize() int {
|
|
|
|
return sr.value.Size()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) ValueTo(buf []byte) (int, error) {
|
|
|
|
return sr.value.MarshalTo(buf)
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) Value() []byte {
|
2015-10-28 16:26:01 +01:00
|
|
|
buf := make([]byte, sr.ValueSize())
|
|
|
|
n, _ := sr.ValueTo(buf)
|
|
|
|
return buf[:n]
|
2015-08-25 20:52:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) DocID() []byte {
|
|
|
|
return sr.docID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) DocNum() uint64 {
|
|
|
|
return sr.docNum
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sr *StoredRow) String() string {
|
|
|
|
return fmt.Sprintf("StoredRow - Field: %d\n", sr.field) +
|
|
|
|
fmt.Sprintf("DocID '%s' - % x\n", sr.docID, sr.docID) +
|
|
|
|
fmt.Sprintf("DocNum %d\n", sr.docNum) +
|
|
|
|
fmt.Sprintf("Array Positions:\n%v", sr.arrayPositions) +
|
|
|
|
fmt.Sprintf("Value: % x", sr.value.GetRaw())
|
|
|
|
}
|
|
|
|
|
|
|
|
func StoredIteratorStartDocID(docID []byte) []byte {
|
|
|
|
docLen := len(docID)
|
|
|
|
buf := make([]byte, 1+docLen+1)
|
|
|
|
buf[0] = 's'
|
|
|
|
copy(buf[1:], docID)
|
|
|
|
buf[1+docLen] = ByteSeparator
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
|
|
|
func StoredPrefixDocIDNum(docID []byte, docNum uint64) []byte {
|
|
|
|
docLen := len(docID)
|
|
|
|
buf := make([]byte, 1+docLen+1+binary.MaxVarintLen64)
|
|
|
|
buf[0] = 's'
|
|
|
|
copy(buf[1:], docID)
|
|
|
|
buf[1+docLen] = ByteSeparator
|
|
|
|
bytesUsed := 1 + docLen + 1
|
|
|
|
bytesUsed += binary.PutUvarint(buf[bytesUsed:], docNum)
|
|
|
|
return buf[0:bytesUsed]
|
|
|
|
}
|