-
Notifications
You must be signed in to change notification settings - Fork 118
/
object.go
161 lines (146 loc) · 3.41 KB
/
object.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package db
import (
"fmt"
)
const (
// Separator of the key segment
Separator = ":"
// ObjectEncodingLength indecate current object marshaled length
ObjectEncodingLength = 42
)
// ObjectEncoding is the encoding type of an object
type ObjectEncoding byte
// Encoding values, see https://github.com/antirez/redis/blob/unstable/src/server.h#L581
const (
ObjectEncodingRaw = ObjectEncoding(iota)
ObjectEncodingInt
ObjectEncodingHT
ObjectEncodingZipmap
ObjectEncodingLinkedlist
ObjectEncodingZiplist
ObjectEncodingIntset
ObjectEncodingSkiplist
ObjectEncodingEmbstr
ObjectEncodingQuicklist
)
// String representation of ObjectEncoding
func (enc ObjectEncoding) String() string {
switch enc {
case ObjectEncodingRaw:
return "raw"
case ObjectEncodingInt:
return "int"
case ObjectEncodingHT:
return "hashtable"
case ObjectEncodingZipmap:
return "zipmap"
case ObjectEncodingLinkedlist:
return "linkedlist"
case ObjectEncodingZiplist:
return "ziplist"
case ObjectEncodingIntset:
return "intset"
case ObjectEncodingSkiplist:
return "skiplist"
case ObjectEncodingEmbstr:
return "embstr"
case ObjectEncodingQuicklist:
return "quicklist"
default:
return "unknown"
}
}
// ObjectType is the type of a data structure
type ObjectType byte
// String representation of object type
func (t ObjectType) String() string {
switch t {
case ObjectString:
return "string"
case ObjectList:
return "list"
case ObjectSet:
return "set"
case ObjectZSet:
return "zset"
case ObjectHash:
return "hash"
}
return "none"
}
// Object types, see https://github.com/antirez/redis/blob/unstable/src/server.h#L461
const (
ObjectString = ObjectType(iota)
ObjectList
ObjectSet
ObjectZSet
ObjectHash
)
// Object meta schema
// Layout {DB}:{TAG}:{Key}
// DB [0-255]
// Key Usersapce key
// TAG M(Meta), D(Data)
// Object data schema
// Layout: {DB}:{TAG}:{ID}:{Others}
// ID Object ID, ID is not used for meta
// String schema (associated value with meta)
// Layout: {DB}:M:{key}
type Object struct {
ID []byte
Type ObjectType //refer to redis
Encoding ObjectEncoding //refer to redis
CreatedAt int64
UpdatedAt int64
ExpireAt int64
}
// String representation of an object
func (obj *Object) String() string {
return fmt.Sprintf("ID:%s type:%s encoding:%s createdat:%d updatedat:%d expireat:%d",
UUIDString(obj.ID), obj.Type, obj.Encoding, obj.CreatedAt, obj.UpdatedAt, obj.ExpireAt)
}
// Object returns the object associated with the key
func (txn *Transaction) Object(key []byte) (*Object, error) {
mkey := MetaKey(txn.db, key)
obj, err := getObject(txn, mkey)
if err != nil {
return nil, err
}
if IsExpired(obj, Now()) {
return nil, ErrKeyNotFound
}
return obj, nil
}
// Destory the object
func (txn *Transaction) Destory(obj *Object, key []byte) error {
mkey := MetaKey(txn.db, key)
dkey := DataKey(txn.db, obj.ID)
if err := txn.t.Delete(mkey); err != nil {
return err
}
if obj.Type != ObjectString {
if err := gc(txn.t, dkey); err != nil {
return err
}
}
if obj.ExpireAt > 0 {
if err := unExpireAt(txn.t, mkey, obj.ExpireAt); err != nil {
return err
}
}
return nil
}
func getObject(txn *Transaction, metaKey []byte) (*Object, error) {
meta, err := txn.t.Get(metaKey)
if err != nil {
if IsErrNotFound(err) {
return nil, ErrKeyNotFound
}
return nil, err
}
obj, err := DecodeObject(meta)
if err != nil {
return nil, err
}
return obj, nil
}