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

lightningnetwork / lnd / 13566028875

27 Feb 2025 12:09PM UTC coverage: 49.396% (-9.4%) from 58.748%
13566028875

Pull #9555

github

ellemouton
graph/db: populate the graph cache in Start instead of during construction

In this commit, we move the graph cache population logic out of the
ChannelGraph constructor and into its Start method instead.
Pull Request #9555: graph: extract cache from CRUD [6]

34 of 54 new or added lines in 4 files covered. (62.96%)

27464 existing lines in 436 files now uncovered.

101095 of 204664 relevant lines covered (49.4%)

1.54 hits per line

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

47.06
/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) {
3✔
43
        var meta *Meta
3✔
44

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

54
        return meta, nil
3✔
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✔
60
        metaBucket := tx.ReadBucket(metaBucket)
3✔
61
        if metaBucket == nil {
6✔
62
                return ErrMetaNotFound
3✔
63
        }
3✔
64

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

72
        return nil
3✔
73
}
74

75
// PutMeta writes the passed instance of the database met-data struct to disk.
UNCOV
76
func (d *DB) PutMeta(meta *Meta) error {
×
UNCOV
77
        return kvdb.Update(d, func(tx kvdb.RwTx) error {
×
UNCOV
78
                return putMeta(meta, tx)
×
UNCOV
79
        }, func() {})
×
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 {
3✔
86
        metaBucket, err := tx.CreateTopLevelBucket(metaBucket)
3✔
87
        if err != nil {
3✔
88
                return err
×
89
        }
×
90

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

94
func putDbVersion(metaBucket kvdb.RwBucket, meta *Meta) error {
3✔
95
        scratch := make([]byte, 4)
3✔
96
        byteOrder.PutUint32(scratch, meta.DbVersionNumber)
3✔
97
        return metaBucket.Put(dbVersionKey, scratch)
3✔
98
}
3✔
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 {
3✔
108
        s := ""
3✔
109
        for index, name := range om.Versions {
3✔
UNCOV
110
                s += fmt.Sprintf("%d: %s", index, name)
×
UNCOV
111
        }
×
112
        if s == "" {
6✔
113
                s = "empty"
3✔
114
        }
3✔
115
        return s
3✔
116
}
117

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

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

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

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

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

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

158
        return om, nil
3✔
159
}
160

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

UNCOV
169
                var b bytes.Buffer
×
UNCOV
170

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

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

UNCOV
185
                return metaBucket.Put(optionalVersionKey, b.Bytes())
×
UNCOV
186
        }, func() {})
×
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) {
3✔
193
        markerBucket := tx.ReadBucket(markerKey)
3✔
194
        if markerBucket == nil {
6✔
195
                return nil, ErrMarkerNotPresent
3✔
196
        }
3✔
197

UNCOV
198
        val := markerBucket.Get(markerKey)
×
UNCOV
199

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

UNCOV
208
        return val, nil
×
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 {
3✔
214
        marker, err := CheckMarkerPresent(tx, TombstoneKey)
3✔
215
        if err == ErrMarkerNotPresent {
6✔
216
                // No marker present, so no tombstone. The DB is still alive.
3✔
217
                return nil
3✔
218
        }
3✔
UNCOV
219
        if err != nil {
×
220
                return err
×
221
        }
×
222

223
        // There was no error so there is a tombstone marker/tag. We cannot use
224
        // this DB anymore.
UNCOV
225
        return fmt.Errorf("refusing to use db, it was marked with a tombstone "+
×
UNCOV
226
                "after successful data migration; tombstone reads: %s",
×
UNCOV
227
                string(marker))
×
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)
UNCOV
235
func AddMarker(tx kvdb.RwTx, markerKey, markerValue []byte) error {
×
UNCOV
236
        if len(markerValue) == 0 {
×
237
                return fmt.Errorf("marker value cannot be empty")
×
238
        }
×
239

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

UNCOV
245
        return markerBucket.Put(markerKey, markerValue)
×
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