forked from coreos/torus
/
blockset_main.go
160 lines (142 loc) · 4.26 KB
/
blockset_main.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
// blockset provides a registry of BlockLayers, that can be (Un)Marshaled
// and retrieve blocks from a Torus storage interface. This is the package
// which allows abstractions atop individual files, such as error correction,
// redundancy checking, further replication, and the like.
package blockset
import (
"errors"
"fmt"
"strings"
"github.com/coreos/pkg/capnslog"
"github.com/coreos/torus"
"github.com/coreos/torus/models"
"github.com/prometheus/client_golang/prometheus"
)
var clog = capnslog.NewPackageLogger("github.com/coreos/torus", "blockset")
var (
promCRCFail = prometheus.NewCounter(prometheus.CounterOpts{
Name: "torus_blockset_crc_failed_blocks",
Help: "Number of blocks that failed due to CRC mismatch",
})
promBaseFail = prometheus.NewCounter(prometheus.CounterOpts{
Name: "torus_blockset_base_failed_blocks",
Help: "Number of blocks that failed",
})
)
func init() {
prometheus.MustRegister(promCRCFail)
prometheus.MustRegister(promBaseFail)
}
type blockset interface {
torus.Blockset
makeID(torus.INodeRef) torus.BlockRef
setStore(store torus.BlockStore)
getStore() torus.BlockStore
}
// Constants for each type of layer, for serializing/deserializing
const (
Base torus.BlockLayerKind = iota
CRC
Replication
)
// CreateBlocksetFunc is the signature of a constructor used to create
// a BlockLayer.
type CreateBlocksetFunc func(opts string, store torus.BlockStore, subLayer blockset) (blockset, error)
var blocklayerRegistry map[torus.BlockLayerKind]CreateBlocksetFunc
// RegisterBlockset is the hook used for implementations of
// blocksets to register themselves to the system. This is usually
// called in the init() of the package that implements the blockset.
func RegisterBlockset(b torus.BlockLayerKind, newFunc CreateBlocksetFunc) {
if blocklayerRegistry == nil {
blocklayerRegistry = make(map[torus.BlockLayerKind]CreateBlocksetFunc)
}
if _, ok := blocklayerRegistry[b]; ok {
panic("torus: attempted to register BlockLayer " + string(b) + " twice")
}
blocklayerRegistry[b] = newFunc
}
// CreateBlockset creates a Blockset of type b, with serialized data, backing store, and subLayer, if any)
// with the provided address.
func CreateBlockset(b torus.BlockLayer, store torus.BlockStore, subLayer blockset) (torus.Blockset, error) {
return createBlockset(b, store, subLayer)
}
func createBlockset(b torus.BlockLayer, store torus.BlockStore, subLayer blockset) (blockset, error) {
return blocklayerRegistry[b.Kind](b.Options, store, subLayer)
}
func UnmarshalFromProto(layers []*models.BlockLayer, store torus.BlockStore) (torus.Blockset, error) {
l := len(layers)
var layer blockset
if l == 0 {
return nil, errors.New("No layers to unmarshal")
}
for i := l - 1; i >= 0; i-- {
m := layers[i]
// Options must be stored by the blockset when serialized
newl, err := createBlockset(torus.BlockLayer{Kind: torus.BlockLayerKind(m.Type), Options: ""}, store, layer)
if err != nil {
return nil, err
}
err = newl.Unmarshal(m.Content)
if err != nil {
return nil, err
}
layer = newl
}
return layer, nil
}
func CreateBlocksetFromSpec(spec torus.BlockLayerSpec, store torus.BlockStore) (torus.Blockset, error) {
l := len(spec)
var layer blockset
if l == 0 {
return nil, errors.New("Empty spec")
}
for i := l - 1; i >= 0; i-- {
m := spec[i]
newl, err := createBlockset(m, store, layer)
if err != nil {
return nil, err
}
layer = newl
}
return layer, nil
}
func ParseBlockLayerKind(s string) (torus.BlockLayerKind, error) {
smalls := strings.ToLower(s)
switch smalls {
case "base":
return Base, nil
case "crc":
return CRC, nil
case "rep", "r":
return Replication, nil
default:
return torus.BlockLayerKind(-1), fmt.Errorf("no such block layer type: %s", s)
}
}
func ParseBlockLayerSpec(s string) (torus.BlockLayerSpec, error) {
var out torus.BlockLayerSpec
ss := strings.Split(s, ",")
for _, x := range ss {
opts := strings.Split(x, "=")
k, err := ParseBlockLayerKind(opts[0])
if err != nil {
return nil, err
}
var opt string
if len(opts) > 1 {
opt = opts[1]
}
out = append(out, torus.BlockLayer{
Kind: k,
Options: opt,
})
}
return out, nil
}
func MustParseBlockLayerSpec(s string) torus.BlockLayerSpec {
out, err := ParseBlockLayerSpec(s)
if err != nil {
panic(err)
}
return out
}