-
Notifications
You must be signed in to change notification settings - Fork 0
/
scheme.go
157 lines (143 loc) · 4.5 KB
/
scheme.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
package stored
import (
"encoding/json"
"fmt"
"reflect"
"github.com/apple/foundationdb/bindings/go/src/fdb"
"github.com/apple/foundationdb/bindings/go/src/fdb/directory"
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
)
// STORED support up to 255 versions of each object
// when you change object (for eaxmple change type of an field) new version is created
// once there will be 100 versions ahead STORED will perform transactional database update
// updating all outdated records to the newest version
// note: any large field (> than 100kb should be marked as mutable for the performance)
type schemeFull struct { // stored separately, an key for each version
versions map[uint64]schemeVersion `json:"versions"`
latest uint64 `json:"latest"`
current schemeVersion `json:"-"`
}
type schemeVersion struct {
PrimaryFields []schemeField `json:"primary"` // Fields stored inside primary part of key
PackedFields []schemeField `json:"packed"` // Fields stored at one-key packed body
MutableFields []schemeField `json:"mutable"` // Fields stored as separate keys (mutable keys)
Created int64 `json:"timestamp"` // Time the scheme was created
}
// schemeField is needed to match data in diferent position of the value with fields of object
// since annotated name of field or real name could be changes STORED will match field if one
// of those preserved
type schemeField struct {
Name string `json:"name"`
ObjectName string `json:"obj_name"`
Type string `json:"type"`
}
func (sf *schemeFull) load(ob *ObjectBuilder, dir directory.DirectorySubspace, tr fdb.ReadTransaction) error {
sub := dir.Sub("scheme")
start, end := sub.FDBRangeKeys()
r := fdb.KeyRange{Begin: start, End: end}
rangeGet := tr.GetRange(r, fdb.RangeOptions{
Mode: fdb.StreamingModeWantAll,
})
rows, err := rangeGet.GetSliceWithError()
if err != nil {
return err
}
sf.versions = map[uint64]schemeVersion{}
for _, kv := range rows {
sch := schemeVersion{}
err := json.Unmarshal(kv.Value, &sch)
if err != nil {
fmt.Println("scheme corrupted", err)
ob.panic("scheme corrupted")
}
var tuple tuple.Tuple
tuple, err = sub.Unpack(kv.Key)
if err != nil {
fmt.Println("scheme corrupted", err)
ob.panic("scheme corrupted")
}
version := tuple[0].(uint64)
sf.versions[version] = sch
}
sf.setLatest()
return nil
}
func (sf *schemeFull) setLatest() *schemeVersion {
latestTime := int64(0)
latestVer := uint64(0)
for ver, scheme := range sf.versions {
if scheme.Created > latestTime {
latestVer = ver
latestTime = scheme.Created
}
}
if latestVer != 0 {
v := sf.versions[latestVer]
return &v
}
return nil
}
func (sf *schemeFull) buildCurrent(ob *ObjectBuilder) {
sf.current = schemeVersion{
PrimaryFields: []schemeField{},
PackedFields: []schemeField{},
MutableFields: []schemeField{},
}
for _, field := range ob.object.primaryFields {
sf.current.PrimaryFields = append(sf.current.PrimaryFields, sf.current.wrapField(field))
}
for _, field := range ob.object.getFields() {
if field.primary {
continue
}
if field.mutable {
sf.current.MutableFields = append(sf.current.MutableFields, sf.current.wrapField(field))
} else {
sf.current.PackedFields = append(sf.current.PackedFields, sf.current.wrapField(field))
}
}
}
// compare returns true if new version should be stored
func (sf *schemeFull) compare(new *schemeVersion, old *schemeVersion) bool {
if new.Created < old.Created {
return false // just in case comparing outdated version
}
if len(new.PrimaryFields) != len(old.PrimaryFields) {
return true // new version should be set up
}
if !reflect.DeepEqual(new.PrimaryFields, old.PrimaryFields) {
return true
}
if len(new.PackedFields) != len(old.PackedFields) {
return true
}
for k, newField := range new.PackedFields {
oldField := old.PackedFields[k]
if newField.Name != oldField.Name && newField.ObjectName != oldField.ObjectName {
return true
}
if newField.Type != oldField.Type {
return true
}
}
if len(new.MutableFields) != len(old.MutableFields) {
return true
}
for k, newField := range new.MutableFields {
oldField := old.MutableFields[k]
if newField.Name != oldField.Name && newField.ObjectName != oldField.ObjectName {
return true
}
if newField.Type != oldField.Type {
return true
}
}
return false
}
func (sv *schemeVersion) wrapField(field *Field) schemeField {
return schemeField{
Name: field.Name,
ObjectName: field.Type.Name,
Type: field.Type.Type.Name(),
}
}