Skip to content

Commit

Permalink
updated to add new test cases and small changes
Browse files Browse the repository at this point in the history
  • Loading branch information
gregns1 committed Oct 8, 2024
1 parent 3d3c510 commit a0a346a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 35 deletions.
17 changes: 4 additions & 13 deletions base/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1021,9 +1021,6 @@ func HexCasToUint64(cas string) uint64 {
// HexCasToUint64ForDelta will convert hex cas to uint64 accounting for any stripped zeros in delta calculation
func HexCasToUint64ForDelta(casByte []byte) (uint64, error) {
var decoded []byte
if len(casByte) <= 2 {
return 0, fmt.Errorf("hex value is too short")
}

// as we strip any zeros off the end of the hex value for deltas, the input delta could be odd length
if len(casByte)%2 != 0 {
Expand Down Expand Up @@ -1055,14 +1052,16 @@ func HexCasToUint64ForDelta(casByte []byte) (uint64, error) {
}

// Uint64ToLittleEndianHexAndStripZeros will convert a uint64 type to little endian hex, stripping any zeros off the end
// + stripping 0x from start
func Uint64ToLittleEndianHexAndStripZeros(cas uint64) string {
hexCas := Uint64CASToLittleEndianHexNo0x(cas)
hexCas := Uint64CASToLittleEndianHex(cas)

i := len(hexCas) - 1
for i > 2 && hexCas[i] == '0' {
i--
}
return string(hexCas[:i+1])
// strip 0x from start
return string(hexCas[2 : i+1])
}

func HexToBase64(s string) ([]byte, error) {
Expand All @@ -1075,14 +1074,6 @@ func HexToBase64(s string) ([]byte, error) {
return encoded, nil
}

func Uint64CASToLittleEndianHexNo0x(cas uint64) []byte {
littleEndian := make([]byte, 8)
binary.LittleEndian.PutUint64(littleEndian, cas)
encodedArray := make([]byte, hex.EncodedLen(8))
_ = hex.Encode(encodedArray, littleEndian)
return encodedArray
}

func CasToString(cas uint64) string {
return string(Uint64CASToLittleEndianHex(cas))
}
Expand Down
7 changes: 7 additions & 0 deletions base/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1764,4 +1764,11 @@ func TestUint64CASToLittleEndianHexAndStripZeros(t *testing.T) {
u64Stripped, err = HexCasToUint64ForDelta([]byte(hexLEStripped))
require.NoError(t, err)
assert.Equal(t, u64, u64Stripped)

hexLE = "0xa500000000000000"
u64 = HexCasToUint64(hexLE)
hexLEStripped = Uint64ToLittleEndianHexAndStripZeros(u64)
u64Stripped, err = HexCasToUint64ForDelta([]byte(hexLEStripped))
require.NoError(t, err)
assert.Equal(t, u64, u64Stripped)
}
51 changes: 29 additions & 22 deletions db/hybrid_logical_vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (vde VersionsDeltas) Swap(i, j int) {

func (vde VersionsDeltas) Less(i, j int) bool {
if vde[i].Value == vde[j].Value {
return vde[i].SourceID < vde[j].SourceID
return false
}
return vde[i].Value < vde[j].Value
}
Expand All @@ -58,6 +58,11 @@ func VersionDeltas(versions map[string]uint64) VersionsDeltas {
vdm = append(vdm, CreateVersion(src, vrs))
}

// return early for single entry
if len(vdm) == 1 {
return vdm
}

// sort the list
sort.Sort(vdm)

Expand All @@ -77,10 +82,7 @@ func VersionsToDeltas(m map[string]uint64) []string {
var vrsList []string
deltas := VersionDeltas(m)
for _, delta := range deltas {
key := delta.SourceID
val := delta.Value
encodedVal := base.Uint64ToLittleEndianHexAndStripZeros(val)
listItem := encodedVal + "@" + key
listItem := delta.StringForVersionDelta()
vrsList = append(vrsList, listItem)
}

Expand Down Expand Up @@ -142,6 +144,13 @@ func (v Version) String() string {
return strconv.FormatUint(v.Value, 16) + "@" + v.SourceID
}

// StringForVersionDelta will take a version struct and convert the value to delta format
// (encoding it to LE hex, stripping any 0's off the end and stripping leading 0x)
func (v Version) StringForVersionDelta() string {
encodedVal := base.Uint64ToLittleEndianHexAndStripZeros(v.Value)
return encodedVal + "@" + v.SourceID
}

// ExtractCurrentVersionFromHLV will take the current version form the HLV struct and return it in the Version struct
func (hlv *HybridLogicalVector) ExtractCurrentVersionFromHLV() *Version {
src, vrs := hlv.GetCurrentVersion()
Expand All @@ -159,16 +168,6 @@ type HybridLogicalVector struct {
PreviousVersions HLVVersions // map of previous versions for fast efficient lookup
}

// constants for the json fields of the bucket version vector
const (
jsonCvCAS = "cvCas"
jsonImportCAS = "importCAS"
jsonSourceID = "src"
jsonVersionCAS = "ver"
jsonMergeVersion = "mv"
jsonPreviousVersion = "pv"
)

// NewHybridLogicalVector returns an initialised HybridLogicalVector.
func NewHybridLogicalVector() HybridLogicalVector {
return HybridLogicalVector{
Expand Down Expand Up @@ -528,30 +527,38 @@ func CreateEncodedSourceID(bucketUUID, clusterUUID string) (string, error) {
}

func (hlv HybridLogicalVector) MarshalJSON() ([]byte, error) {
type BucketVector struct {
CurrentVersionCAS string `json:"cvCas,omitempty"`
ImportCAS string `json:"importCAS,omitempty"`
SourceID string `json:"src"`
Version string `json:"ver"`
PV *[]string `json:"pv,omitempty"`
MV *[]string `json:"mv,omitempty"`
}
var cvCas string
var importCAS string
var vrsCas string

bucketHLV := make(map[string]interface{})
var bucketHLV = BucketVector{}
if hlv.CurrentVersionCAS != 0 {
cvCas = base.CasToString(hlv.CurrentVersionCAS)
bucketHLV[jsonCvCAS] = cvCas
bucketHLV.CurrentVersionCAS = cvCas
}
if hlv.ImportCAS != 0 {
importCAS = base.CasToString(hlv.ImportCAS)
bucketHLV[jsonImportCAS] = importCAS
bucketHLV.ImportCAS = importCAS
}
vrsCas = base.CasToString(hlv.Version)
bucketHLV[jsonVersionCAS] = vrsCas
bucketHLV[jsonSourceID] = hlv.SourceID
bucketHLV.Version = vrsCas
bucketHLV.SourceID = hlv.SourceID

pvPersistedFormat := VersionsToDeltas(hlv.PreviousVersions)
if len(pvPersistedFormat) > 0 {
bucketHLV[jsonPreviousVersion] = pvPersistedFormat
bucketHLV.PV = &pvPersistedFormat
}
mvPersistedFormat := VersionsToDeltas(hlv.MergeVersions)
if len(mvPersistedFormat) > 0 {
bucketHLV[jsonMergeVersion] = mvPersistedFormat
bucketHLV.MV = &mvPersistedFormat
}

return base.JSONMarshal(&bucketHLV)
Expand Down
28 changes: 28 additions & 0 deletions db/hybrid_logical_vector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ func TestParseCBLVersion(t *testing.T) {
// - Create a test HLV and convert it to persisted format in bytes
// - Convert this back to in memory format, assert each elem of in memory format previous versions map is the same as
// the corresponding element in the original pvMap
// - Do the same for a pv map that will have two entries with the same version value
// - Do the same as above but for nil maps
func TestVersionDeltaCalculation(t *testing.T) {
src1 := "src1"
Expand Down Expand Up @@ -529,6 +530,33 @@ func TestVersionDeltaCalculation(t *testing.T) {
assert.Equal(t, expCas, memHLV.CurrentVersionCAS)
assert.Len(t, memHLV.MergeVersions, 0)

// test hlv with two pv version entries that are equal to each other
hlv = createHLVForTest(t, inputHLVA)
// make src3 have the same version value as src2
pvMap[src3] = pvMap[src2]
hlv.PreviousVersions = pvMap

// convert hlv to persisted format
vvXattr, err = base.JSONMarshal(&hlv)
require.NoError(t, err)

// convert the bytes back to an in memory format of hlv
memHLV = NewHybridLogicalVector()
err = base.JSONUnmarshal(vvXattr, &memHLV)
require.NoError(t, err)

assert.Equal(t, pvMap[src1], memHLV.PreviousVersions[src1])
assert.Equal(t, pvMap[src2], memHLV.PreviousVersions[src2])
assert.Equal(t, pvMap[src3], memHLV.PreviousVersions[src3])
assert.Equal(t, pvMap[src4], memHLV.PreviousVersions[src4])
assert.Equal(t, pvMap[src5], memHLV.PreviousVersions[src5])

// assert that the other elements are as expected
assert.Equal(t, expSrc, memHLV.SourceID)
assert.Equal(t, expVal, memHLV.Version)
assert.Equal(t, expCas, memHLV.CurrentVersionCAS)
assert.Len(t, memHLV.MergeVersions, 0)

// test hlv with nil merge versions and nil previous versions to test panic safe
pvMap = nil
hlv2 := createHLVForTest(t, inputHLVA)
Expand Down

0 comments on commit a0a346a

Please sign in to comment.