Repository: nutsdb/nutsdb

Issue:
refactor: Move set to internal package
**Is your feature request related to a problem? Please describe.**
For now, set should not be a visibility struct out of nutsdb project, so we need to move it to internal package to make it private.

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


Discussion:

Solution patch:
diff --git a/.gitignore b/.gitignore
index 1b4c7b6..00e762c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ bin/
 */*.DS_Store
 .gocache
 .vscode
-coverage.out
\ No newline at end of file
+coverage.out
+coverage.html
\ No newline at end of file
diff --git a/index.go b/index.go
index da7ac50..1557139 100644
--- a/index.go
+++ b/index.go
@@ -17,7 +17,7 @@ package nutsdb
 import "github.com/nutsdb/nutsdb/internal/data"
 
 type IdxType interface {
-	data.BTree | Set | SortedSet | data.List
+	data.BTree | data.Set | SortedSet | data.List
 }
 
 type defaultOp[T IdxType] struct {
@@ -74,12 +74,12 @@ func (idx BTreeIdx) getWithDefault(id BucketId) *data.BTree {
 }
 
 type SetIdx struct {
-	*defaultOp[Set]
+	*defaultOp[data.Set]
 }
 
-func (idx SetIdx) getWithDefault(id BucketId) *Set {
-	return idx.defaultOp.computeIfAbsent(id, func() *Set {
-		return NewSet()
+func (idx SetIdx) getWithDefault(id BucketId) *data.Set {
+	return idx.defaultOp.computeIfAbsent(id, func() *data.Set {
+		return data.NewSet()
 	})
 }
 
@@ -110,7 +110,7 @@ func newIndexWithOptions(opts Options) *index {
 	i.opts = opts
 	i.list = ListIdx{defaultOp: &defaultOp[data.List]{idx: map[BucketId]*data.List{}}, opts: opts}
 	i.bTree = BTreeIdx{&defaultOp[data.BTree]{idx: map[BucketId]*data.BTree{}}}
-	i.set = SetIdx{&defaultOp[Set]{idx: map[BucketId]*Set{}}}
+	i.set = SetIdx{&defaultOp[data.Set]{idx: map[BucketId]*data.Set{}}}
 	i.sortedSet = SortedSetIdx{&defaultOp[SortedSet]{idx: map[BucketId]*SortedSet{}}}
 	return i
 }
diff --git a/internal/data/set.go b/internal/data/set.go
index a739ce6..e4cbb50 100644
--- a/internal/data/set.go
+++ b/internal/data/set.go
@@ -1,6 +1,24 @@
+// Copyright 2023 The nutsdb Author. All rights reserved.
+//
+// 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 data
 
-import "errors"
+import (
+	"errors"
+
+	"github.com/nutsdb/nutsdb/internal/utils"
+)
 
 var (
 	// ErrSetNotExist is returned when the key does not exist.
@@ -12,3 +30,230 @@ var (
 	// ErrMemberEmpty is returned when the item received is nil
 	ErrMemberEmpty = errors.New("item empty")
 )
+
+type Set struct {
+	M map[string]map[uint32]*Record
+}
+
+func NewSet() *Set {
+	return &Set{
+		M: map[string]map[uint32]*Record{},
+	}
+}
+
+// SAdd adds the specified members to the set stored at key.
+func (s *Set) SAdd(key string, values [][]byte, records []*Record) error {
+	set, ok := s.M[key]
+	if !ok {
+		s.M[key] = map[uint32]*Record{}
+		set = s.M[key]
+	}
+
+	for i, value := range values {
+		hash, err := utils.GetFnv32(value)
+		if err != nil {
+			return err
+		}
+		set[hash] = records[i]
+	}
+
+	return nil
+}
+
+// SRem removes the specified members from the set stored at key.
+func (s *Set) SRem(key string, values ...[]byte) error {
+	set, ok := s.M[key]
+	if !ok {
+		return ErrSetNotExist
+	}
+
+	if len(values) == 0 || values[0] == nil {
+		return ErrMemberEmpty
+	}
+
+	for _, value := range values {
+		hash, err := utils.GetFnv32(value)
+		if err != nil {
+			return err
+		}
+		delete(set, hash)
+	}
+
+	return nil
+}
+
+// SHasKey returns whether it has the set at given key.
+func (s *Set) SHasKey(key string) bool {
+	if _, ok := s.M[key]; ok {
+		return true
+	}
+	return false
+}
+
+// SPop removes and returns one or more random elements from the set value store at key.
+func (s *Set) SPop(key string) *Record {
+	if !s.SHasKey(key) {
+		return nil
+	}
+
+	for hash, record := range s.M[key] {
+		delete(s.M[key], hash)
+		return record
+	}
+
+	return nil
+}
+
+// SCard Returns the set cardinality (number of elements) of the set stored at key.
+func (s *Set) SCard(key string) int {
+	if !s.SHasKey(key) {
+		return 0
+	}
+
+	return len(s.M[key])
+}
+
+// SDiff Returns the members of the set resulting from the difference between the first set and all the successive sets.
+func (s *Set) SDiff(key1, key2 string) ([]*Record, error) {
+	if !s.SHasKey(key1) || !s.SHasKey(key2) {
+		return nil, ErrSetNotExist
+	}
+
+	records := make([]*Record, 0)
+
+	for hash, record := range s.M[key1] {
+		if _, ok := s.M[key2][hash]; !ok {
+			records = append(records, record)
+		}
+	}
+	return records, nil
+}
+
+// SInter Returns the members of the set resulting from the intersection of all the given sets.
+func (s *Set) SInter(key1, key2 string) ([]*Record, error) {
+	if !s.SHasKey(key1) || !s.SHasKey(key2) {
+		return nil, ErrSetNotExist
+	}
+
+	records := make([]*Record, 0)
+
+	for hash, record := range s.M[key1] {
+		if _, ok := s.M[key2][hash]; ok {
+			records = append(records, record)
+		}
+	}
+	return records, nil
+}
+
+// SIsMember Returns if member is a member of the set stored at key.
+func (s *Set) SIsMember(key string, value []byte) (bool, error) {
+	if _, ok := s.M[key]; !ok {
+		return false, ErrSetNotExist
+	}
+
+	hash, err := utils.GetFnv32(value)
+	if err != nil {
+		return false, err
+	}
+
+	if _, ok := s.M[key][hash]; ok {
+		return true, nil
+	}
+
+	return false, nil
+}
+
+// SAreMembers Returns if members are members of the set stored at key.
+// For multiple items it returns true only if all the items exist.
+func (s *Set) SAreMembers(key string, values ...[]byte) (bool, error) {
+	if _, ok := s.M[key]; !ok {
+		return false, ErrSetNotExist
+	}
+
+	for _, value := range values {
+
+		hash, err := utils.GetFnv32(value)
+		if err != nil {
+			return false, err
+		}
+
+		if _, ok := s.M[key][hash]; !ok {
+			return false, nil
+		}
+	}
+
+	return true, nil
+}
+
+// SMembers returns all the members of the set value stored at key.
+func (s *Set) SMembers(key string) ([]*Record, error) {
+	if _, ok := s.M[key]; !ok {
+		return nil, ErrSetNotExist
+	}
+
+	records := make([]*Record, 0)
+
+	for _, record := range s.M[key] {
+		records = append(records, record)
+	}
+
+	return records, nil
+}
+
+// SMove moves member from the set at source to the set at destination.
+func (s *Set) SMove(key1, key2 string, value []byte) (bool, error) {
+	if !s.SHasKey(key1) || !s.SHasKey(key2) {
+		return false, ErrSetNotExist
+	}
+
+	set1, set2 := s.M[key1], s.M[key2]
+
+	hash, err := utils.GetFnv32(value)
+	if err != nil {
+		return false, err
+	}
+
+	var (
+		member *Record
+		ok     bool
+	)
+
+	if member, ok = set1[hash]; !ok {
+		return false, ErrSetMemberNotExist
+	}
+
+	if _, ok = set2[hash]; !ok {
+		err = s.SAdd(key2, [][]byte{value}, []*Record{member})
+		if err != nil {
+			return false, err
+		}
+	}
+
+	err = s.SRem(key1, value)
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+// SUnion returns the members of the set resulting from the union of all the given sets.
+func (s *Set) SUnion(key1, key2 string) ([]*Record, error) {
+	if !s.SHasKey(key1) || !s.SHasKey(key2) {
+		return nil, ErrSetNotExist
+	}
+
+	records, err := s.SMembers(key1)
+
+	if err != nil {
+		return nil, err
+	}
+
+	for hash, record := range s.M[key2] {
+		if _, ok := s.M[key1][hash]; !ok {
+			records = append(records, record)
+		}
+	}
+
+	return records, nil
+}
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index 1ee148b..5dce643 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -4,11 +4,24 @@ import (
 	"bytes"
 	"encoding/binary"
 	"errors"
+	"hash/fnv"
 	"io"
 	"path/filepath"
 	"reflect"
 )
 
+var fnvHash = fnv.New32a()
+
+func GetFnv32(value []byte) (uint32, error) {
+	_, err := fnvHash.Write(value)
+	if err != nil {
+		return 0, err
+	}
+	hash := fnvHash.Sum32()
+	fnvHash.Reset()
+	return hash, nil
+}
+
 func ConvertBigEndianBytesToUint64(data []byte) uint64 {
 	return binary.BigEndian.Uint64(data)
 }
diff --git a/set.go b/set.go
deleted file mode 100644
index be27593..0000000
--- a/set.go
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2023 The nutsdb Author. All rights reserved.
-//
-// 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 nutsdb
-
-import (
-	"hash/fnv"
-
-	"github.com/nutsdb/nutsdb/internal/data"
-)
-
-var (
-	// ErrSetNotExist is returned when the key does not exist.
-	ErrSetNotExist = data.ErrSetNotExist
-
-	// ErrSetMemberNotExist is returned when the member of set does not exist
-	ErrSetMemberNotExist = data.ErrSetMemberNotExist
-
-	// ErrMemberEmpty is returned when the item received is nil
-	ErrMemberEmpty = data.ErrMemberEmpty
-)
-
-var fnvHash = fnv.New32a()
-
-type Set struct {
-	M map[string]map[uint32]*data.Record
-}
-
-func NewSet() *Set {
-	return &Set{
-		M: map[string]map[uint32]*data.Record{},
-	}
-}
-
-// SAdd adds the specified members to the set stored at key.
-func (s *Set) SAdd(key string, values [][]byte, records []*data.Record) error {
-	set, ok := s.M[key]
-	if !ok {
-		s.M[key] = map[uint32]*data.Record{}
-		set = s.M[key]
-	}
-
-	for i, value := range values {
-		hash, err := getFnv32(value)
-		if err != nil {
-			return err
-		}
-		set[hash] = records[i]
-	}
-
-	return nil
-}
-
-// SRem removes the specified members from the set stored at key.
-func (s *Set) SRem(key string, values ...[]byte) error {
-	set, ok := s.M[key]
-	if !ok {
-		return ErrSetNotExist
-	}
-
-	if len(values) == 0 || values[0] == nil {
-		return ErrMemberEmpty
-	}
-
-	for _, value := range values {
-		hash, err := getFnv32(value)
-		if err != nil {
-			return err
-		}
-		delete(set, hash)
-	}
-
-	return nil
-}
-
-// SHasKey returns whether it has the set at given key.
-func (s *Set) SHasKey(key string) bool {
-	if _, ok := s.M[key]; ok {
-		return true
-	}
-	return false
-}
-
-// SPop removes and returns one or more random elements from the set value store at key.
-func (s *Set) SPop(key string) *data.Record {
-	if !s.SHasKey(key) {
-		return nil
-	}
-
-	for hash, record := range s.M[key] {
-		delete(s.M[key], hash)
-		return record
-	}
-
-	return nil
-}
-
-// SCard Returns the set cardinality (number of elements) of the set stored at key.
-func (s *Set) SCard(key string) int {
-	if !s.SHasKey(key) {
-		return 0
-	}
-
-	return len(s.M[key])
-}
-
-// SDiff Returns the members of the set resulting from the difference between the first set and all the successive sets.
-func (s *Set) SDiff(key1, key2 string) ([]*data.Record, error) {
-	if !s.SHasKey(key1) || !s.SHasKey(key2) {
-		return nil, ErrSetNotExist
-	}
-
-	records := make([]*data.Record, 0)
-
-	for hash, record := range s.M[key1] {
-		if _, ok := s.M[key2][hash]; !ok {
-			records = append(records, record)
-		}
-	}
-	return records, nil
-}
-
-// SInter Returns the members of the set resulting from the intersection of all the given sets.
-func (s *Set) SInter(key1, key2 string) ([]*data.Record, error) {
-	if !s.SHasKey(key1) || !s.SHasKey(key2) {
-		return nil, ErrSetNotExist
-	}
-
-	records := make([]*data.Record, 0)
-
-	for hash, record := range s.M[key1] {
-		if _, ok := s.M[key2][hash]; ok {
-			records = append(records, record)
-		}
-	}
-	return records, nil
-}
-
-// SIsMember Returns if member is a member of the set stored at key.
-func (s *Set) SIsMember(key string, value []byte) (bool, error) {
-	if _, ok := s.M[key]; !ok {
-		return false, ErrSetNotExist
-	}
-
-	hash, err := getFnv32(value)
-	if err != nil {
-		return false, err
-	}
-
-	if _, ok := s.M[key][hash]; ok {
-		return true, nil
-	}
-
-	return false, nil
-}
-
-// SAreMembers Returns if members are members of the set stored at key.
-// For multiple items it returns true only if all the items exist.
-func (s *Set) SAreMembers(key string, values ...[]byte) (bool, error) {
-	if _, ok := s.M[key]; !ok {
-		return false, ErrSetNotExist
-	}
-
-	for _, value := range values {
-
-		hash, err := getFnv32(value)
-		if err != nil {
-			return false, err
-		}
-
-		if _, ok := s.M[key][hash]; !ok {
-			return false, nil
-		}
-	}
-
-	return true, nil
-}
-
-// SMembers returns all the members of the set value stored at key.
-func (s *Set) SMembers(key string) ([]*data.Record, error) {
-	if _, ok := s.M[key]; !ok {
-		return nil, ErrSetNotExist
-	}
-
-	records := make([]*data.Record, 0)
-
-	for _, record := range s.M[key] {
-		records = append(records, record)
-	}
-
-	return records, nil
-}
-
-// SMove moves member from the set at source to the set at destination.
-func (s *Set) SMove(key1, key2 string, value []byte) (bool, error) {
-	if !s.SHasKey(key1) || !s.SHasKey(key2) {
-		return false, ErrSetNotExist
-	}
-
-	set1, set2 := s.M[key1], s.M[key2]
-
-	hash, err := getFnv32(value)
-	if err != nil {
-		return false, err
-	}
-
-	var (
-		member *data.Record
-		ok     bool
-	)
-
-	if member, ok = set1[hash]; !ok {
-		return false, ErrSetMemberNotExist
-	}
-
-	if _, ok = set2[hash]; !ok {
-		err = s.SAdd(key2, [][]byte{value}, []*data.Record{member})
-		if err != nil {
-			return false, err
-		}
-	}
-
-	err = s.SRem(key1, value)
-	if err != nil {
-		return false, err
-	}
-
-	return true, nil
-}
-
-// SUnion returns the members of the set resulting from the union of all the given sets.
-func (s *Set) SUnion(key1, key2 string) ([]*data.Record, error) {
-	if !s.SHasKey(key1) || !s.SHasKey(key2) {
-		return nil, ErrSetNotExist
-	}
-
-	records, err := s.SMembers(key1)
-
-	if err != nil {
-		return nil, err
-	}
-
-	for hash, record := range s.M[key2] {
-		if _, ok := s.M[key1][hash]; !ok {
-			records = append(records, record)
-		}
-	}
-
-	return records, nil
-}
diff --git a/sorted_set.go b/sorted_set.go
index c6b7b98..1873d3e 100644
--- a/sorted_set.go
+++ b/sorted_set.go
@@ -20,6 +20,7 @@ import (
 	"math/rand"
 
 	"github.com/nutsdb/nutsdb/internal/data"
+	"github.com/nutsdb/nutsdb/internal/utils"
 )
 
 var (
@@ -180,7 +181,7 @@ func (z *SortedSet) ZRangeByRank(key string, start int, end int) ([]*data.Record
 
 func (z *SortedSet) ZRem(key string, value []byte) (*data.Record, error) {
 	if sortedSet, ok := z.M[key]; ok {
-		hash, err := getFnv32(value)
+		hash, err := utils.GetFnv32(value)
 		if err != nil {
 			return nil, err
 		}
@@ -214,7 +215,7 @@ func (z *SortedSet) getZRemRangeByRankNodes(key string, start int, end int) ([]*
 
 func (z *SortedSet) ZRank(key string, value []byte) (int, error) {
 	if sortedSet, ok := z.M[key]; ok {
-		hash, err := getFnv32(value)
+		hash, err := utils.GetFnv32(value)
 		if err != nil {
 			return 0, err
 		}
@@ -229,7 +230,7 @@ func (z *SortedSet) ZRank(key string, value []byte) (int, error) {
 
 func (z *SortedSet) ZRevRank(key string, value []byte) (int, error) {
 	if sortedSet, ok := z.M[key]; ok {
-		hash, err := getFnv32(value)
+		hash, err := utils.GetFnv32(value)
 		if err != nil {
 			return 0, err
 		}
@@ -255,7 +256,7 @@ func (z *SortedSet) ZScore(key string, value []byte) (float64, error) {
 
 func (z *SortedSet) ZExist(key string, value []byte) (bool, error) {
 	if sortedSet, ok := z.M[key]; ok {
-		hash, err := getFnv32(value)
+		hash, err := utils.GetFnv32(value)
 		if err != nil {
 			return false, err
 		}
@@ -337,7 +338,7 @@ func newSkipList(db *DB) *SkipList {
 		level: 1,
 		dict:  make(map[uint32]*SkipListNode),
 	}
-	hash, _ := getFnv32([]byte(""))
+	hash, _ := utils.GetFnv32([]byte(""))
 	skipList.header = createNode(SkipListMaxLevel, 0, hash, nil)
 	return skipList
 }
@@ -516,7 +517,7 @@ func (sl *SkipList) PopMax() *SkipListNode {
 func (sl *SkipList) Put(score SCORE, value []byte, record *data.Record) error {
 	var newNode *SkipListNode
 
-	hash, _ := getFnv32(value)
+	hash, _ := utils.GetFnv32(value)
 
 	if n, ok := sl.dict[hash]; ok {
 		// score does not change, only update value
@@ -768,7 +769,7 @@ func (sl *SkipList) GetByRank(rank int, remove bool) *SkipListNode {
 //
 // Time complexity : O(1).
 func (sl *SkipList) GetByValue(value []byte) *SkipListNode {
-	hash, _ := getFnv32(value)
+	hash, _ := utils.GetFnv32(value)
 	return sl.dict[hash]
 }
 
diff --git a/tx_set.go b/tx_set.go
index b207f7e..966569c 100644
--- a/tx_set.go
+++ b/tx_set.go
@@ -22,6 +22,17 @@ import (
 	"github.com/pkg/errors"
 )
 
+var (
+	// ErrSetNotExist is returned when the key does not exist.
+	ErrSetNotExist = data.ErrSetNotExist
+
+	// ErrSetMemberNotExist is returned when the member of set does not exist
+	ErrSetMemberNotExist = data.ErrSetMemberNotExist
+
+	// ErrMemberEmpty is returned when the item received is nil
+	ErrMemberEmpty = data.ErrMemberEmpty
+)
+
 func (tx *Tx) sPut(bucket string, key []byte, dataFlag uint16, values ...[]byte) error {
 
 	if dataFlag == DataSetFlag {
@@ -45,7 +56,7 @@ func (tx *Tx) sPut(bucket string, key []byte, dataFlag uint16, values ...[]byte)
 		}
 
 		for _, value := range values {
-			hash, err := getFnv32(value)
+			hash, err := utils.GetFnv32(value)
 			if err != nil {
 				return err
 			}
@@ -274,7 +285,7 @@ func (tx *Tx) SDiffByTwoBuckets(bucket1 string, key1 []byte, bucket2 string, key
 	}
 
 	var (
-		set1, set2 *Set
+		set1, set2 *data.Set
 		ok         bool
 	)
 
@@ -338,7 +349,7 @@ func (tx *Tx) SMoveByTwoBuckets(bucket1 string, key1 []byte, bucket2 string, key
 	}
 
 	var (
-		set1, set2 *Set
+		set1, set2 *data.Set
 		ok         bool
 	)
 
@@ -370,7 +381,7 @@ func (tx *Tx) SMoveByTwoBuckets(bucket1 string, key1 []byte, bucket2 string, key
 		return false, ErrNotFoundKeyInBucket(bucket2, key2)
 	}
 
-	hash, err := getFnv32(item)
+	hash, err := utils.GetFnv32(item)
 	if err != nil {
 		return false, err
 	}
@@ -429,7 +440,7 @@ func (tx *Tx) SUnionByTwoBuckets(bucket1 string, key1 []byte, bucket2 string, ke
 	}
 
 	var (
-		set1, set2 *Set
+		set1, set2 *data.Set
 		ok         bool
 	)
 	b1, err := tx.db.bm.GetBucket(DataStructureSet, bucket1)
diff --git a/utils.go b/utils.go
index 9a140be..62846ea 100644
--- a/utils.go
+++ b/utils.go
@@ -70,16 +70,6 @@ func splitStringFloat64Str(str, separator string) (string, float64) {
 	return firstItem, secondItem
 }
 
-func getFnv32(value []byte) (uint32, error) {
-	_, err := fnvHash.Write(value)
-	if err != nil {
-		return 0, err
-	}
-	hash := fnvHash.Sum32()
-	fnvHash.Reset()
-	return hash, nil
-}
-
 func createNewBufferWithSize(size int) *bytes.Buffer {
 	buf := new(bytes.Buffer)
 	buf.Grow(int(size))



Test patch:
diff --git a/set_test.go b/internal/data/set_test.go
similarity index 89%
rename from set_test.go
rename to internal/data/set_test.go
index b01f3d1..237ee55 100644
--- a/set_test.go
+++ b/internal/data/set_test.go
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package nutsdb
+package data
 
 import (
 	"testing"
 
-	"github.com/nutsdb/nutsdb/internal/data"
 	"github.com/nutsdb/nutsdb/internal/testutils"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 func TestSet_SAdd(t *testing.T) {
 	set := NewSet()
 	key := "key"
-	expectRecords := data.GenerateRecords(3)
+	expectRecords := GenerateRecords(3)
 
 	values := make([][]byte, 3)
 	for i := range expectRecords {
@@ -42,7 +42,7 @@ func TestSet_SAdd(t *testing.T) {
 func TestSet_SRem(t *testing.T) {
 	set := NewSet()
 	key := "key"
-	expectRecords := data.GenerateRecords(4)
+	expectRecords := GenerateRecords(4)
 	values := make([][]byte, 4)
 	for i := range expectRecords {
 		values[i] = expectRecords[i].Value
@@ -68,7 +68,7 @@ func TestSet_SDiff(t *testing.T) {
 	key3 := "set3"
 	key4 := "set4"
 
-	expectRecords := data.GenerateRecords(10)
+	expectRecords := GenerateRecords(10)
 
 	values := make([][]byte, 10)
 	for i := range expectRecords {
@@ -89,7 +89,7 @@ func TestSet_SDiff(t *testing.T) {
 		name    string
 		args    args
 		set     *Set
-		want    []*data.Record
+		want    []*Record
 		wantErr bool
 	}{
 		{"normal set diff1", args{key1, key2}, set, expectRecords[:2], false},
@@ -119,7 +119,7 @@ func TestSet_SCard(t *testing.T) {
 	key3 := "set3"
 	key4 := "set4"
 
-	expectRecords := data.GenerateRecords(10)
+	expectRecords := GenerateRecords(10)
 
 	values := make([][]byte, 10)
 	for i := range expectRecords {
@@ -159,7 +159,7 @@ func TestSet_SInter(t *testing.T) {
 	key3 := "set3"
 	key4 := "set4"
 
-	expectRecords := data.GenerateRecords(10)
+	expectRecords := GenerateRecords(10)
 
 	values := make([][]byte, 10)
 	for i := range expectRecords {
@@ -180,11 +180,11 @@ func TestSet_SInter(t *testing.T) {
 		name    string
 		args    args
 		set     *Set
-		want    []*data.Record
+		want    []*Record
 		wantErr bool
 	}{
-		{"normal set inter1", args{key1, key2}, set, []*data.Record{expectRecords[2], expectRecords[3], expectRecords[4]}, false},
-		{"normal set inter1", args{key2, key3}, set, []*data.Record{expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[5]}, false},
+		{"normal set inter1", args{key1, key2}, set, []*Record{expectRecords[2], expectRecords[3], expectRecords[4]}, false},
+		{"normal set inter1", args{key2, key3}, set, []*Record{expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[5]}, false},
 		{"normal set inter2", args{key1, key4}, set, nil, false},
 		{"first fake set", args{"fake_key1", key2}, set, nil, true},
 		{"second fake set", args{key1, "fake_key2"}, set, nil, true},
@@ -207,7 +207,7 @@ func TestSet_SMembers(t *testing.T) {
 
 	key := "set"
 
-	expectRecords := data.GenerateRecords(3)
+	expectRecords := GenerateRecords(3)
 
 	values := make([][]byte, 3)
 	for i := range expectRecords {
@@ -220,7 +220,7 @@ func TestSet_SMembers(t *testing.T) {
 		name    string
 		key     string
 		set     *Set
-		want    []*data.Record
+		want    []*Record
 		wantErr bool
 	}{
 		{"normal SMembers", key, set, expectRecords[0:1], false},
@@ -246,7 +246,7 @@ func TestSet_SMove(t *testing.T) {
 	key1 := "set1"
 	key2 := "set2"
 
-	expectRecords := data.GenerateRecords(3)
+	expectRecords := GenerateRecords(3)
 	values := make([][]byte, 3)
 	for i := range expectRecords {
 		values[i] = expectRecords[i].Value
@@ -265,8 +265,8 @@ func TestSet_SMove(t *testing.T) {
 		name      string
 		args      args
 		set       *Set
-		want1     []*data.Record
-		want2     []*data.Record
+		want1     []*Record
+		want2     []*Record
 		expectErr error
 	}{
 		{"normal SMove", args{key1, key2, values[1]}, set, expectRecords[0:1], expectRecords[1:], nil},
@@ -296,12 +296,12 @@ func TestSet_SPop(t *testing.T) {
 
 	key := "set"
 
-	expectRecords := data.GenerateRecords(2)
+	expectRecords := GenerateRecords(2)
 	values := make([][]byte, 2)
 	for i := range expectRecords {
 		values[i] = expectRecords[i].Value
 	}
-	m := map[*data.Record]struct{}{}
+	m := map[*Record]struct{}{}
 	for _, expectRecord := range expectRecords {
 		m[expectRecord] = struct{}{}
 	}
@@ -326,6 +326,12 @@ func TestSet_SPop(t *testing.T) {
 			require.Equal(t, tt.ok, ok)
 		})
 	}
+
+	t.Run("set SPop key not found", func(t *testing.T) {
+		s := NewSet()
+		rec := s.SPop("not_found_key")
+		assert.Nil(t, rec)
+	})
 }
 
 func TestSet_SIsMember(t *testing.T) {
@@ -333,7 +339,7 @@ func TestSet_SIsMember(t *testing.T) {
 
 	key := "key"
 
-	expectRecords := data.GenerateRecords(1)
+	expectRecords := GenerateRecords(1)
 	values := [][]byte{expectRecords[0].Value}
 
 	require.NoError(t, set.SAdd(key, values, expectRecords))
@@ -362,7 +368,7 @@ func TestSet_SAreMembers(t *testing.T) {
 
 	key := "set"
 
-	expectRecords := data.GenerateRecords(4)
+	expectRecords := GenerateRecords(4)
 	values := make([][]byte, 4)
 	for i := range expectRecords {
 		values[i] = expectRecords[i].Value
@@ -399,7 +405,7 @@ func TestSet_SUnion(t *testing.T) {
 	key3 := "set3"
 	key4 := "set4"
 
-	expectRecords := data.GenerateRecords(10)
+	expectRecords := GenerateRecords(10)
 
 	values := make([][]byte, 10)
 	for i := range expectRecords {
@@ -420,15 +426,15 @@ func TestSet_SUnion(t *testing.T) {
 		name    string
 		args    args
 		set     *Set
-		want    []*data.Record
+		want    []*Record
 		wantErr bool
 	}{
 		{"normal set Union1", args{key1, key4}, set,
-			[]*data.Record{expectRecords[0], expectRecords[1], expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[7], expectRecords[8], expectRecords[9]},
+			[]*Record{expectRecords[0], expectRecords[1], expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[7], expectRecords[8], expectRecords[9]},
 			false},
 		{
 			"normal set Union2", args{key2, key3}, set,
-			[]*data.Record{expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[5], expectRecords[6]},
+			[]*Record{expectRecords[2], expectRecords[3], expectRecords[4], expectRecords[5], expectRecords[6]},
 			false,
 		},
 		{"first fake set", args{"fake_key1", key2}, set, nil, true},
diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go
index 2179d7d..d650be8 100644
--- a/internal/utils/utils_test.go
+++ b/internal/utils/utils_test.go
@@ -80,3 +80,12 @@ func TestEncodeListKeyAndDecodeListKey(t *testing.T) {
 	assert.Equal(t, key, newKey)
 	assert.Equal(t, seq, newSeq)
 }
+
+func TestFnvHash32(t *testing.T) {
+	t.Run("test hash32", func(t *testing.T) {
+		bytes := []byte("test-fnv-hash32")
+		hash_result, err := utils.GetFnv32(bytes)
+		assert.NoError(t, err)
+		assert.Equal(t, uint32(1486366400), hash_result)
+	})
+}
diff --git a/tx_zset_test.go b/tx_zset_test.go
index 56448ab..6451100 100644
--- a/tx_zset_test.go
+++ b/tx_zset_test.go
@@ -19,6 +19,7 @@ import (
 	"testing"
 
 	"github.com/nutsdb/nutsdb/internal/testutils"
+	"github.com/nutsdb/nutsdb/internal/utils"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -503,7 +504,7 @@ func TestTx_ZSetEntryIdxMode_HintKeyValAndRAMIdxMode(t *testing.T) {
 		require.NoError(t, err)
 
 		zset := db.Index.sortedSet.getWithDefault(1, db).M[string(key)]
-		hash, _ := getFnv32(value)
+		hash, _ := utils.GetFnv32(value)
 		node := zset.dict[hash]
 
 		require.NotNil(t, node.record.Value)
@@ -531,7 +532,7 @@ func TestTx_ZSetEntryIdxMode_HintKeyAndRAMIdxMode(t *testing.T) {
 		require.NoError(t, err)
 
 		zset := db.Index.sortedSet.getWithDefault(1, db).M[string(key)]
-		hash, _ := getFnv32(value)
+		hash, _ := utils.GetFnv32(value)
 		node := zset.dict[hash]
 
 		require.Nil(t, node.record.Value)