This repository has been archived by the owner on Nov 2, 2018. It is now read-only.
/
boltdb.go
89 lines (79 loc) · 2.07 KB
/
boltdb.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
package persist
import (
"time"
"github.com/coreos/bbolt"
)
// BoltDatabase is a persist-level wrapper for the bolt database, providing
// extra information such as a version number.
type BoltDatabase struct {
Metadata
*bolt.DB
}
// checkMetadata confirms that the metadata in the database is
// correct. If there is no metadata, correct metadata is inserted
func (db *BoltDatabase) checkMetadata(md Metadata) error {
err := db.Update(func(tx *bolt.Tx) error {
// Check if the database has metadata. If not, create metadata for the
// database.
bucket := tx.Bucket([]byte("Metadata"))
if bucket == nil {
err := db.updateMetadata(tx)
if err != nil {
return err
}
return nil
}
// Verify that the metadata matches the expected metadata.
header := bucket.Get([]byte("Header"))
if string(header) != md.Header {
return ErrBadHeader
}
version := bucket.Get([]byte("Version"))
if string(version) != md.Version {
return ErrBadVersion
}
return nil
})
return err
}
// updateMetadata will set the contents of the metadata bucket to the values
// in db.Metadata.
func (db *BoltDatabase) updateMetadata(tx *bolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists([]byte("Metadata"))
if err != nil {
return err
}
err = bucket.Put([]byte("Header"), []byte(db.Header))
if err != nil {
return err
}
err = bucket.Put([]byte("Version"), []byte(db.Version))
if err != nil {
return err
}
return nil
}
// Close closes the database.
func (db *BoltDatabase) Close() error {
return db.DB.Close()
}
// OpenDatabase opens a database and validates its metadata.
func OpenDatabase(md Metadata, filename string) (*BoltDatabase, error) {
// Open the database using a 3 second timeout (without the timeout,
// database will potentially hang indefinitely.
db, err := bolt.Open(filename, 0600, &bolt.Options{Timeout: 3 * time.Second})
if err != nil {
return nil, err
}
// Check the metadata.
boltDB := &BoltDatabase{
Metadata: md,
DB: db,
}
err = boltDB.checkMetadata(md)
if err != nil {
db.Close()
return nil, err
}
return boltDB, nil
}