4 Star 0 Fork 1

wanttobeamaster/gridbase

Create your Gitee Account
Explore and code with more than 14 million developers,Free private repositories !:)
Sign up
文件
Clone or Download
bolt_engine_set.go 6.16 KB
Copy Edit Raw Blame History
wanttobeamaster authored 2021-06-06 11:10 +08:00 . merge mars
package storage
import (
"bytes"
bolt "gitee.com/wanttobeamaster/bbolt"
"gitee.com/wanttobeamaster/gridbase/pkg/util"
"math/rand"
"time"
)
type SetObj struct {
Size uint64
}
func MarshalSetObj(obj *SetObj) []byte {
totalLen := 8
raw := make([]byte, totalLen)
idx := 0
util.Uint64ToBytes1(raw[idx:], obj.Size)
return raw
}
func UnmarshalSetObj(raw []byte) (*SetObj, error) {
if len(raw) != 8 {
return nil, nil
}
obj := SetObj{}
idx := 0
obj.Size, _ = util.BytesToUint64(raw[idx:])
return &obj, nil
}
func (e *boltSetEngine) SetMetaObj(key []byte) (*SetObj, bool, error) {
var (
v []byte
err error
)
metaKey := RawKeyPrefix(key)
err = e.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
v = b.Get(metaKey)
return nil
})
if err != nil {
return nil, false, err
}
if v == nil {
return nil, false, nil
}
obj, err := UnmarshalSetObj(v)
if err != nil {
return nil, false, nil
}
return obj, false, nil
}
func (e *boltSetEngine) newSetMetaObj() *SetObj {
return &SetObj{
Size: 0,
}
}
func (e *boltSetEngine) RawSetDataKey(key, member []byte) []byte {
keyPrefix := RawKeyPrefix(key)
dataKey := append(keyPrefix, util.DataTypeKey)
dataKey = append(dataKey, member...)
return dataKey
}
type boltSetEngine struct {
db *bolt.DB
limiter util.Limiter
}
func newBoltSetEngine(db *bolt.DB) SetEngine {
db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte("boltSetBucket"))
if err != nil {
return err
}
return nil
})
return &boltSetEngine{
db: db,
limiter: *util.NewLimiter(LimitConcurrencyWrite),
}
}
//SAdd adds members into specified Set
func (e *boltSetEngine) SAdd(key []byte, members ...[]byte) (int64, error) {
if len(key) == 0 {
return 0, ErrEmptyKey
}
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return 0, err
}
if metaObj == nil {
metaObj = e.newSetMetaObj()
}
var added uint64
batchErr := e.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
for _, member := range members {
eDataKey := e.RawSetDataKey(key, member)
v := b.Get(eDataKey)
if v != nil {
//already exists
} else {
added++
err := b.Put(eDataKey, []byte{0})
if err != nil {
return err
}
}
}
metaObj.Size += added
//update meta
eMetaKey := RawKeyPrefix(key)
eMetaValue := MarshalSetObj(metaObj)
err := b.Put(eMetaKey, eMetaValue)
if err != nil {
return err
}
return nil
})
return int64(added), batchErr
}
//SRem removes members from specified Set
func (e *boltSetEngine) SRem(key []byte, members ...[]byte) (int64, error) {
if len(key) == 0 || len(members) == 0 {
return 0, ErrEmptyKey
}
var removed uint64
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return 0, err
}
if metaObj == nil {
metaObj = e.newSetMetaObj()
}
batchErr := e.db.Batch(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
for _, member := range members {
eDataKey := e.RawSetDataKey(key, member)
v := b.Get(eDataKey)
if v == nil {
//already exists
} else {
removed++
err := b.Delete(eDataKey)
if err != nil {
return err
}
}
}
if removed > 0 {
eMetaKey := RawKeyPrefix(key)
//update meta
metaObj.Size -= removed
//update meta
if metaObj.Size > 0 {
eMetaValue := MarshalSetObj(metaObj)
err := b.Put(eMetaKey, eMetaValue)
if err != nil {
return err
}
} else {
//Set.Size == 0, delete meta
err := b.Delete(eMetaKey)
if err != nil {
return err
}
}
}
return nil
})
return int64(removed), batchErr
}
func (e *boltSetEngine) SCard(key []byte) (int64, error) {
if len(key) == 0 {
return 0, ErrEmptyKey
}
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return 0, err
}
if metaObj == nil {
metaObj = e.newSetMetaObj()
}
return int64(metaObj.Size), err
}
func (e *boltSetEngine) SMembers(key []byte) ([][]byte, error) {
if len(key) == 0 {
return nil, ErrEmptyKey
}
var members [][]byte
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return nil, err
}
if metaObj == nil {
metaObj = e.newSetMetaObj()
}
startKey := e.RawSetDataKey(key, nil)
endKey := KVPrefixNext(startKey)
metaKeyLen := len(RawKeyPrefix(key))
e.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
c := b.Cursor()
for k, _ := c.Seek(startKey); k != nil && bytes.Compare(k, endKey) <= 0; k, _ = c.Next() {
members = append(members, k[metaKeyLen+1:])
}
return nil
})
return members, nil
}
func (e *boltSetEngine) SIsMember(key []byte, member []byte) (int64, error) {
if len(key) == 0 || len(member) == 0 {
return 0, ErrEmptyKey
}
var err error
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return 0, err
}
if metaObj == nil {
return 0, nil
}
eDataKey := e.RawSetDataKey(key, member)
var v []byte
err = e.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
v = b.Get(eDataKey)
return nil
})
if err != nil {
return 0, err
}
if v == nil {
return 0, nil
}
return 1, nil
}
func (e *boltSetEngine) SPop(key []byte) ([]byte, error) {
if len(key) == 0 {
return nil, ErrEmptyKey
}
metaObj, _, err := e.SetMetaObj(key)
if err != nil {
return nil, err
}
if metaObj == nil {
return nil, nil
}
if metaObj.Size == 0 {
return nil, nil
}
eDataKeyPrefix := e.RawSetDataKey(key, nil)
rand.Seed(time.Now().UnixNano())
deleteCnt := rand.Intn(int(metaObj.Size))
var deleteKey []byte
updateErr := e.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("boltSetBucket"))
c := b.Cursor()
deleteKey, _ = c.Seek(eDataKeyPrefix)
for i := deleteCnt; i > 0; i-- {
deleteKey, _ = c.Next()
}
err := b.Delete(deleteKey)
if err != nil {
return err
}
eMetaKey := RawKeyPrefix(key)
//update meta
metaObj.Size--
//update meta
if metaObj.Size > 0 {
eMetaValue := MarshalSetObj(metaObj)
err := b.Put(eMetaKey, eMetaValue)
if err != nil {
return err
}
} else {
//Set.Size == 0, delete meta
err := b.Delete(eMetaKey)
if err != nil {
return err
}
}
return nil
})
if updateErr != nil {
return nil, updateErr
}
//return member, nil
return deleteKey[len(eDataKeyPrefix):], nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wanttobeamaster/gridbase.git
git@gitee.com:wanttobeamaster/gridbase.git
wanttobeamaster
gridbase
gridbase
a9a2a47d54bb

Search