/
opdatastore.go
128 lines (105 loc) · 2.47 KB
/
opdatastore.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
package main
import (
"fmt"
"github.com/denkhaus/bitshares/gen/data"
"github.com/denkhaus/bitshares/types"
"github.com/denkhaus/logging"
"github.com/juju/errors"
"github.com/mitchellh/reflectwalk"
"github.com/stretchr/objx"
)
//OperationBlob simply counts fields and child map elements.
//The more fields, the more telling is the structure.
type OperationBlob struct {
data map[string]interface{}
rank int
}
func (p *OperationBlob) Enter(loc reflectwalk.Location) error {
p.rank++
return nil
}
func (p *OperationBlob) Exit(loc reflectwalk.Location) error {
return nil
}
func (p *OperationBlob) String() string {
return fmt.Sprintf("rank: %d", p.rank)
}
func (p *OperationBlob) Analyze() error {
if err := reflectwalk.Walk(p.data, p); err != nil {
return errors.Annotate(err, "Walk")
}
return nil
}
func NewOperationBlob(data map[string]interface{}) *OperationBlob {
s := OperationBlob{
data: data,
}
return &s
}
type OpDataStore map[types.OperationType]map[int]*OperationBlob
func (p *OpDataStore) Init(m data.OperationSampleMap, ch chan GenData) error {
if len(m) == 0 {
logging.Warn("init datastore: no sample data loaded")
return nil
}
logging.Info("init datastore")
for typ, d := range m {
for idx, data := range d {
opData, err := objx.FromJSON(data)
if err != nil {
return errors.Annotate(err, "FromJSON")
}
_, err = p.Insert(typ, NewOperationBlob(opData), 0)
if err != nil {
return errors.Annotate(err, "Insert")
}
if idx >= 0 {
ch <- GenData{
Type: typ,
SampleIdx: idx,
Data: opData,
}
}
}
}
return nil
}
func (p *OpDataStore) MustInsert(typ types.OperationType, rank int) int {
blobs, ok := (*p)[typ]
if ok {
for _, bl := range blobs {
if bl.rank == rank {
return -1
}
}
return len(blobs)
}
return 0
}
func (p *OpDataStore) Insert(typ types.OperationType, blob *OperationBlob, block uint64) (int, error) {
if err := blob.Analyze(); err != nil {
return -1, errors.Annotate(err, "Analyze")
}
idx := p.MustInsert(typ, blob.rank)
if idx < 0 {
return idx, nil
}
if idx == 0 {
(*p)[typ] = map[int]*OperationBlob{0: blob}
logging.Infof("Block %d: Blob added for type %v: %s", block, typ, blob)
return idx, nil
}
(*p)[typ][idx] = blob
logging.Infof("Block %d: Blob upgraded for type %v: %s", block, typ, blob)
return idx, nil
}
func NewOpDataStore() *OpDataStore {
s := OpDataStore{}
return &s
}
func max(a, b int) int {
if a > b {
return a
}
return b
}