-
Notifications
You must be signed in to change notification settings - Fork 106
/
metadata.go
145 lines (115 loc) · 3.83 KB
/
metadata.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
package badger
import (
"fmt"
"sync"
"github.com/dgraph-io/badger/v4"
"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
"github.com/oasisprotocol/oasis-core/go/storage/mkvs/db/api"
)
// serializedMetadata is the on-disk serialized metadata.
type serializedMetadata struct {
// Version is the database schema version.
Version uint64 `json:"version"`
// Namespace is the namespace this database is for.
Namespace common.Namespace `json:"namespace"`
// EarliestVersion is the earliest version.
EarliestVersion uint64 `json:"earliest_version"`
// LastFinalizedVersion is the last finalized version.
LastFinalizedVersion *uint64 `json:"last_finalized_version"`
// MultipartVersion is the version for the in-progress multipart restore, or 0 if none was in progress.
MultipartVersion uint64 `json:"multipart_version"`
}
// metadata is the database metadata.
type metadata struct {
sync.RWMutex
value serializedMetadata
}
func (m *metadata) getEarliestVersion() uint64 {
m.RLock()
defer m.RUnlock()
return m.value.EarliestVersion
}
func (m *metadata) setEarliestVersion(tx *badger.Txn, version uint64) error {
m.Lock()
defer m.Unlock()
// The earliest version can only increase, not decrease.
if version < m.value.EarliestVersion {
return nil
}
m.value.EarliestVersion = version
return m.save(tx)
}
func (m *metadata) getLastFinalizedVersion() (uint64, bool) {
m.RLock()
defer m.RUnlock()
if m.value.LastFinalizedVersion == nil {
return 0, false
}
return *m.value.LastFinalizedVersion, true
}
func (m *metadata) setLastFinalizedVersion(tx *badger.Txn, version uint64) error {
m.Lock()
defer m.Unlock()
if m.value.LastFinalizedVersion != nil && version <= *m.value.LastFinalizedVersion {
return nil
}
if m.value.LastFinalizedVersion == nil {
m.value.EarliestVersion = version
}
m.value.LastFinalizedVersion = &version
return m.save(tx)
}
func (m *metadata) getMultipartVersion() uint64 {
m.Lock()
defer m.Unlock()
return m.value.MultipartVersion
}
func (m *metadata) setMultipartVersion(tx *badger.Txn, version uint64) error {
m.Lock()
defer m.Unlock()
m.value.MultipartVersion = version
return m.save(tx)
}
func (m *metadata) save(tx *badger.Txn) error {
return tx.Set(metadataKeyFmt.Encode(), cbor.Marshal(m.value))
}
// updatedNode is an element of the root updated nodes key.
//
// NOTE: Public fields of this structure are part of the on-disk format.
type updatedNode struct {
_ struct{} `cbor:",toarray"` // nolint
Removed bool
Hash hash.Hash
}
// rootsMetadata manages the roots metadata for a given version.
//
// NOTE: Public fields of this structure are part of the on-disk format.
type rootsMetadata struct {
_ struct{} `cbor:",toarray"`
// Roots is the map of a root created in a version to any derived roots (in this or later versions).
Roots map[api.TypedHash][]api.TypedHash
// version is the version this metadata is for.
version uint64
}
// loadRootsMetadata loads the roots metadata for the given version from the database.
func loadRootsMetadata(tx *badger.Txn, version uint64) (*rootsMetadata, error) {
rootsMeta := &rootsMetadata{version: version}
item, err := tx.Get(rootsMetadataKeyFmt.Encode(version))
switch err {
case nil:
if err = item.Value(func(val []byte) error { return cbor.Unmarshal(val, &rootsMeta) }); err != nil {
return nil, fmt.Errorf("mkvs/badger: error reading roots metadata: %w", err)
}
case badger.ErrKeyNotFound:
rootsMeta.Roots = make(map[api.TypedHash][]api.TypedHash)
default:
return nil, fmt.Errorf("mkvs/badger: error reading roots metadata: %w", err)
}
return rootsMeta, nil
}
// save saves the roots metadata to the database.
func (rm *rootsMetadata) save(tx *badger.Txn) error {
return tx.Set(rootsMetadataKeyFmt.Encode(rm.version), cbor.Marshal(rm))
}