• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 12313002221

13 Dec 2024 09:25AM UTC coverage: 57.486% (+8.6%) from 48.92%
12313002221

push

github

web-flow
Merge pull request #9343 from ellemouton/contextGuard

fn: expand the ContextGuard and add tests

101902 of 177264 relevant lines covered (57.49%)

24909.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.15
/channeldb/meta.go
1
package channeldb
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7

8
        "github.com/lightningnetwork/lnd/kvdb"
9
        "github.com/lightningnetwork/lnd/tlv"
10
)
11

12
var (
13
        // metaBucket stores all the meta information concerning the state of
14
        // the database.
15
        metaBucket = []byte("metadata")
16

17
        // dbVersionKey is a boltdb key and it's used for storing/retrieving
18
        // current database version.
19
        dbVersionKey = []byte("dbp")
20

21
        // dbVersionKey is a boltdb key and it's used for storing/retrieving
22
        // a list of optional migrations that have been applied.
23
        optionalVersionKey = []byte("ovk")
24

25
        // TombstoneKey is the key under which we add a tag in the source DB
26
        // after we've successfully and completely migrated it to the target/
27
        // destination DB.
28
        TombstoneKey = []byte("data-migration-tombstone")
29

30
        // ErrMarkerNotPresent is the error that is returned if the queried
31
        // marker is not present in the given database.
32
        ErrMarkerNotPresent = errors.New("marker not present")
33
)
34

35
// Meta structure holds the database meta information.
36
type Meta struct {
37
        // DbVersionNumber is the current schema version of the database.
38
        DbVersionNumber uint32
39
}
40

41
// FetchMeta fetches the metadata from boltdb and returns filled meta structure.
42
func (d *DB) FetchMeta() (*Meta, error) {
1,746✔
43
        var meta *Meta
1,746✔
44

1,746✔
45
        err := kvdb.View(d, func(tx kvdb.RTx) error {
3,492✔
46
                return FetchMeta(meta, tx)
1,746✔
47
        }, func() {
3,492✔
48
                meta = &Meta{}
1,746✔
49
        })
1,746✔
50
        if err != nil {
1,746✔
51
                return nil, err
×
52
        }
×
53

54
        return meta, nil
1,746✔
55
}
56

57
// FetchMeta is a helper function used in order to allow callers to re-use a
58
// database transaction.
59
func FetchMeta(meta *Meta, tx kvdb.RTx) error {
3,660✔
60
        metaBucket := tx.ReadBucket(metaBucket)
3,660✔
61
        if metaBucket == nil {
5,367✔
62
                return ErrMetaNotFound
1,707✔
63
        }
1,707✔
64

65
        data := metaBucket.Get(dbVersionKey)
1,953✔
66
        if data == nil {
1,953✔
67
                meta.DbVersionNumber = getLatestDBVersion(dbVersions)
×
68
        } else {
1,953✔
69
                meta.DbVersionNumber = byteOrder.Uint32(data)
1,953✔
70
        }
1,953✔
71

72
        return nil
1,953✔
73
}
74

75
// PutMeta writes the passed instance of the database met-data struct to disk.
76
func (d *DB) PutMeta(meta *Meta) error {
5✔
77
        return kvdb.Update(d, func(tx kvdb.RwTx) error {
10✔
78
                return putMeta(meta, tx)
5✔
79
        }, func() {})
10✔
80
}
81

82
// putMeta is an internal helper function used in order to allow callers to
83
// re-use a database transaction. See the publicly exported PutMeta method for
84
// more information.
85
func putMeta(meta *Meta, tx kvdb.RwTx) error {
1,715✔
86
        metaBucket, err := tx.CreateTopLevelBucket(metaBucket)
1,715✔
87
        if err != nil {
1,715✔
88
                return err
×
89
        }
×
90

91
        return putDbVersion(metaBucket, meta)
1,715✔
92
}
93

94
func putDbVersion(metaBucket kvdb.RwBucket, meta *Meta) error {
1,715✔
95
        scratch := make([]byte, 4)
1,715✔
96
        byteOrder.PutUint32(scratch, meta.DbVersionNumber)
1,715✔
97
        return metaBucket.Put(dbVersionKey, scratch)
1,715✔
98
}
1,715✔
99

100
// OptionalMeta structure holds the database optional migration information.
101
type OptionalMeta struct {
102
        // Versions is a set that contains the versions that have been applied.
103
        // When saved to disk, only the indexes are stored.
104
        Versions map[uint64]string
105
}
106

107
func (om *OptionalMeta) String() string {
1✔
108
        s := ""
1✔
109
        for index, name := range om.Versions {
2✔
110
                s += fmt.Sprintf("%d: %s", index, name)
1✔
111
        }
1✔
112
        if s == "" {
1✔
113
                s = "empty"
×
114
        }
×
115
        return s
1✔
116
}
117

118
// fetchOptionalMeta reads the optional meta from the database.
119
func (d *DB) fetchOptionalMeta() (*OptionalMeta, error) {
1,741✔
120
        om := &OptionalMeta{
1,741✔
121
                Versions: make(map[uint64]string),
1,741✔
122
        }
1,741✔
123

1,741✔
124
        err := kvdb.View(d, func(tx kvdb.RTx) error {
3,482✔
125
                metaBucket := tx.ReadBucket(metaBucket)
1,741✔
126
                if metaBucket == nil {
1,741✔
127
                        return ErrMetaNotFound
×
128
                }
×
129

130
                vBytes := metaBucket.Get(optionalVersionKey)
1,741✔
131
                // Exit early if nothing found.
1,741✔
132
                if vBytes == nil {
3,479✔
133
                        return nil
1,738✔
134
                }
1,738✔
135

136
                // Read the versions' length.
137
                r := bytes.NewReader(vBytes)
3✔
138
                vLen, err := tlv.ReadVarInt(r, &[8]byte{})
3✔
139
                if err != nil {
3✔
140
                        return err
×
141
                }
×
142

143
                // Write the version index.
144
                for i := uint64(0); i < vLen; i++ {
6✔
145
                        version, err := tlv.ReadVarInt(r, &[8]byte{})
3✔
146
                        if err != nil {
3✔
147
                                return err
×
148
                        }
×
149
                        om.Versions[version] = optionalVersions[i].name
3✔
150
                }
151

152
                return nil
3✔
153
        }, func() {})
1,741✔
154
        if err != nil {
1,741✔
155
                return nil, err
×
156
        }
×
157

158
        return om, nil
1,741✔
159
}
160

161
// putOptionalMeta writes an optional meta to the database.
162
func (d *DB) putOptionalMeta(om *OptionalMeta) error {
2✔
163
        return kvdb.Update(d, func(tx kvdb.RwTx) error {
4✔
164
                metaBucket, err := tx.CreateTopLevelBucket(metaBucket)
2✔
165
                if err != nil {
2✔
166
                        return err
×
167
                }
×
168

169
                var b bytes.Buffer
2✔
170

2✔
171
                // Write the total length.
2✔
172
                err = tlv.WriteVarInt(&b, uint64(len(om.Versions)), &[8]byte{})
2✔
173
                if err != nil {
2✔
174
                        return err
×
175
                }
×
176

177
                // Write the version indexes.
178
                for v := range om.Versions {
4✔
179
                        err := tlv.WriteVarInt(&b, v, &[8]byte{})
2✔
180
                        if err != nil {
2✔
181
                                return err
×
182
                        }
×
183
                }
184

185
                return metaBucket.Put(optionalVersionKey, b.Bytes())
2✔
186
        }, func() {})
2✔
187
}
188

189
// CheckMarkerPresent returns the marker under the requested key or
190
// ErrMarkerNotFound if either the root bucket or the marker key within that
191
// bucket does not exist.
192
func CheckMarkerPresent(tx kvdb.RTx, markerKey []byte) ([]byte, error) {
1,921✔
193
        markerBucket := tx.ReadBucket(markerKey)
1,921✔
194
        if markerBucket == nil {
3,837✔
195
                return nil, ErrMarkerNotPresent
1,916✔
196
        }
1,916✔
197

198
        val := markerBucket.Get(markerKey)
5✔
199

5✔
200
        // If we wrote the marker correctly, we created a bucket _and_ created a
5✔
201
        // key with a non-empty value. It doesn't matter to us whether the key
5✔
202
        // exists or whether its value is empty, to us, it just means the marker
5✔
203
        // isn't there.
5✔
204
        if len(val) == 0 {
6✔
205
                return nil, ErrMarkerNotPresent
1✔
206
        }
1✔
207

208
        return val, nil
4✔
209
}
210

211
// EnsureNoTombstone returns an error if there is a tombstone marker in the DB
212
// of the given transaction.
213
func EnsureNoTombstone(tx kvdb.RTx) error {
1,917✔
214
        marker, err := CheckMarkerPresent(tx, TombstoneKey)
1,917✔
215
        if err == ErrMarkerNotPresent {
3,832✔
216
                // No marker present, so no tombstone. The DB is still alive.
1,915✔
217
                return nil
1,915✔
218
        }
1,915✔
219
        if err != nil {
2✔
220
                return err
×
221
        }
×
222

223
        // There was no error so there is a tombstone marker/tag. We cannot use
224
        // this DB anymore.
225
        return fmt.Errorf("refusing to use db, it was marked with a tombstone "+
2✔
226
                "after successful data migration; tombstone reads: %s",
2✔
227
                string(marker))
2✔
228
}
229

230
// AddMarker adds the marker with the given key into a top level bucket with the
231
// same name. So the structure will look like:
232
//
233
//        marker-key (top level bucket)
234
//            |->   marker-key:marker-value (key/value pair)
235
func AddMarker(tx kvdb.RwTx, markerKey, markerValue []byte) error {
2✔
236
        if len(markerValue) == 0 {
2✔
237
                return fmt.Errorf("marker value cannot be empty")
×
238
        }
×
239

240
        markerBucket, err := tx.CreateTopLevelBucket(markerKey)
2✔
241
        if err != nil {
2✔
242
                return err
×
243
        }
×
244

245
        return markerBucket.Put(markerKey, markerValue)
2✔
246
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc