Skip to content

Commit 629a1c9

Browse files
committed
Rework the data path and db type handling.
This commit modifies the way the data paths are handled. Since there will ultimately be more data associated with each network than just the block database, the data path has been modified to be "namespaced" based on the network. This allows all data associated with a specific network to simply use the data path without having to worry about conflicts with data from other networks. In addition, this commit renames the block database to "blocks" plus a suffix which denotes the database type. This prevents issues that would otherwise arise if the user decides to use a different database type and a file/folder with the same name already eixsts but is of the old database type. For most users this won't matter, but it does provide nice properties for testing and development as well since it makes it easy to go back and forth between database types. This commit also includes code to upgrade the old database paths to the new ones so the change is seamless for the user. Finally, bump the version to 0.2.0.
1 parent 252ecf8 commit 629a1c9

File tree

5 files changed

+123
-49
lines changed

5 files changed

+123
-49
lines changed

blockmanager.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import (
1818

1919
const (
2020
chanBufferSize = 50
21+
22+
// blockDbNamePrefix is the prefix for the block database name. The
23+
// database type is appended to this value to form the full block
24+
// database name.
25+
blockDbNamePrefix = "blocks"
2126
)
2227

2328
// blockMsg packages a bitcoin block message and the peer it came from together
@@ -394,7 +399,13 @@ func newBlockManager(s *server) *blockManager {
394399

395400
// loadBlockDB opens the block database and returns a handle to it.
396401
func loadBlockDB() (btcdb.Db, error) {
397-
dbPath := filepath.Join(cfg.DataDir, activeNetParams.dbName)
402+
// The database name is based on the database type.
403+
dbName := blockDbNamePrefix + "_" + cfg.DbType
404+
if cfg.DbType == "sqlite" {
405+
dbName = dbName + ".db"
406+
}
407+
dbPath := filepath.Join(cfg.DataDir, dbName)
408+
398409
log.Infof("[BMGR] Loading block database from '%s'", dbPath)
399410
db, err := btcdb.OpenDB(cfg.DbType, dbPath)
400411
if err != nil {

config.go

+39-42
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ const (
2525
defaultMaxPeers = 8
2626
defaultBanDuration = time.Hour * 24
2727
defaultVerifyEnabled = false
28+
defaultDbType = "sqlite"
2829
)
2930

3031
var (
3132
defaultConfigFile = filepath.Join(btcdHomeDir(), defaultConfigFilename)
32-
defaultDataDir = filepath.Join(btcdHomeDir(), "db")
33+
defaultDataDir = filepath.Join(btcdHomeDir(), "data")
34+
knownDbTypes = []string{"leveldb", "sqlite"}
3335
)
3436

3537
// config defines the configuration options for btcd.
@@ -58,7 +60,7 @@ type config struct {
5860
UseTor bool `long:"tor" description:"Specifies the proxy server used is a Tor node"`
5961
TestNet3 bool `long:"testnet" description:"Use the test network"`
6062
RegressionTest bool `long:"regtest" description:"Use the regression test network"`
61-
DbType string `long:"dbtype" description:"DB backend to use for Block Chain"`
63+
DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"`
6264
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
6365
}
6466

@@ -99,6 +101,19 @@ func validLogLevel(logLevel string) bool {
99101
return false
100102
}
101103

104+
// validDbType returns whether or not dbType is a supported database type.
105+
func validDbType(dbType string) bool {
106+
// Would be interesting if btcdb had a 'SupportedDBs() []string'
107+
// API to populate this field.
108+
for _, knownType := range knownDbTypes {
109+
if dbType == knownType {
110+
return true
111+
}
112+
}
113+
114+
return false
115+
}
116+
102117
// normalizePeerAddress returns addr with the default peer port appended if
103118
// there is not already a port specified.
104119
func normalizePeerAddress(addr string) string {
@@ -180,6 +195,7 @@ func loadConfig() (*config, []string, error) {
180195
BanDuration: defaultBanDuration,
181196
ConfigFile: defaultConfigFile,
182197
DataDir: defaultDataDir,
198+
DbType: defaultDbType,
183199
}
184200

185201
// Pre-parse the command line options to see if an alternative config
@@ -249,13 +265,32 @@ func loadConfig() (*config, []string, error) {
249265

250266
// Validate debug log level.
251267
if !validLogLevel(cfg.DebugLevel) {
252-
str := "%s: The specified debug level is invalid -- parsed [%v]"
268+
str := "%s: The specified debug level [%v] is invalid"
253269
err := errors.New(fmt.Sprintf(str, "loadConfig", cfg.DebugLevel))
254270
fmt.Fprintln(os.Stderr, err)
255271
parser.WriteHelp(os.Stderr)
256272
return nil, nil, err
257273
}
258274

275+
// Validate database type.
276+
if !validDbType(cfg.DbType) {
277+
str := "%s: The specified database type [%v] is invalid -- " +
278+
"supported types %v"
279+
err := errors.New(fmt.Sprintf(str, "loadConfig", cfg.DbType,
280+
knownDbTypes))
281+
fmt.Fprintln(os.Stderr, err)
282+
parser.WriteHelp(os.Stderr)
283+
return nil, nil, err
284+
}
285+
286+
// Append the network type to the data directory so it is "namespaced"
287+
// per network. In addition to the block database, there are other
288+
// pieces of data that are saved to disk such as address manager state.
289+
// All data is specific to a network, so namespacing the data directory
290+
// means each individual piece of serialized data does not have to
291+
// worry about changing names per network and such.
292+
cfg.DataDir = filepath.Join(cfg.DataDir, activeNetParams.netName)
293+
259294
// Don't allow ban durations that are too short.
260295
if cfg.BanDuration < time.Duration(time.Second) {
261296
str := "%s: The banduration option may not be less than 1s -- parsed [%v]"
@@ -303,45 +338,7 @@ func loadConfig() (*config, []string, error) {
303338
// Add default port to all added peer addresses if needed and remove
304339
// duplicate addresses.
305340
cfg.AddPeers = normalizeAndRemoveDuplicateAddresses(cfg.AddPeers)
306-
cfg.ConnectPeers =
307-
normalizeAndRemoveDuplicateAddresses(cfg.ConnectPeers)
341+
cfg.ConnectPeers = normalizeAndRemoveDuplicateAddresses(cfg.ConnectPeers)
308342

309-
// determine which database backend to use
310-
// would be interesting of btcdb had a 'supportedDBs() []string'
311-
// API to populate this field.
312-
knownDbs := []string{"leveldb", "sqlite"}
313-
defaultDb := "sqlite"
314-
315-
if len(cfg.DbType) == 0 {
316-
// if db was not specified, use heuristic to see what
317-
// type the database is (if the specified database is a
318-
// file then it is sqlite3, if it is a directory assume
319-
// it is leveldb, if not found default to type _____
320-
dbPath := filepath.Join(cfg.DataDir, activeNetParams.dbName)
321-
322-
fi, err := os.Stat(dbPath)
323-
if err == nil {
324-
if fi.IsDir() {
325-
cfg.DbType = "leveldb"
326-
} else {
327-
cfg.DbType = "sqlite"
328-
}
329-
} else {
330-
cfg.DbType = defaultDb
331-
}
332-
} else {
333-
// does checking this here really make sense ?
334-
typeVerified := false
335-
for _, dbtype := range knownDbs {
336-
if cfg.DbType == dbtype {
337-
typeVerified = true
338-
}
339-
}
340-
if typeVerified == false {
341-
err := fmt.Errorf("Specified database type [%v] not in list of supported databases: %v", cfg.DbType, knownDbs)
342-
fmt.Fprintln(os.Stderr, err)
343-
return nil, nil, err
344-
}
345-
}
346343
return &cfg, remainingArgs, nil
347344
}

params.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var activeNetParams = netParams(defaultBtcnet)
1717
// params is used to group parameters for various networks such as the main
1818
// network and test networks.
1919
type params struct {
20-
dbName string
20+
netName string
2121
btcnet btcwire.BitcoinNet
2222
genesisBlock *btcwire.MsgBlock
2323
genesisHash *btcwire.ShaHash
@@ -32,7 +32,7 @@ type params struct {
3232
// mainNetParams contains parameters specific to the main network
3333
// (btcwire.MainNet).
3434
var mainNetParams = params{
35-
dbName: "btcd.db",
35+
netName: "mainnet",
3636
btcnet: btcwire.MainNet,
3737
genesisBlock: btcchain.ChainParams(btcwire.MainNet).GenesisBlock,
3838
genesisHash: btcchain.ChainParams(btcwire.MainNet).GenesisHash,
@@ -52,7 +52,7 @@ var mainNetParams = params{
5252
// regressionParams contains parameters specific to the regression test network
5353
// (btcwire.TestNet).
5454
var regressionParams = params{
55-
dbName: "btcd_regtest.db",
55+
netName: "regtest",
5656
btcnet: btcwire.TestNet,
5757
genesisBlock: btcchain.ChainParams(btcwire.TestNet).GenesisBlock,
5858
genesisHash: btcchain.ChainParams(btcwire.TestNet).GenesisHash,
@@ -67,7 +67,7 @@ var regressionParams = params{
6767
// testNet3Params contains parameters specific to the test network (version 3)
6868
// (btcwire.TestNet3).
6969
var testNet3Params = params{
70-
dbName: "btcd_testnet.db",
70+
netName: "testnet",
7171
btcnet: btcwire.TestNet3,
7272
genesisBlock: btcchain.ChainParams(btcwire.TestNet3).GenesisBlock,
7373
genesisHash: btcchain.ChainParams(btcwire.TestNet3).GenesisHash,

upgrade.go

+67-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,73 @@
44

55
package main
66

7+
import (
8+
"os"
9+
"path/filepath"
10+
)
11+
12+
// upgradeDBPathNet moves the database for a specific network from its
13+
// location prior to btcd version 0.2.0 and uses heuristics to ascertain the old
14+
// database type to rename to the new format.
15+
func upgradeDBPathNet(oldDbPath, netName string) error {
16+
// Prior to version 0.2.0, the database was named the same thing for
17+
// both sqlite and leveldb. Use heuristics to figure out the type
18+
// of the database and move it to the new path and name introduced with
19+
// version 0.2.0 accordingly.
20+
fi, err := os.Stat(oldDbPath)
21+
if err == nil {
22+
oldDbType := "sqlite"
23+
if fi.IsDir() {
24+
oldDbType = "leveldb"
25+
}
26+
27+
// The new database name is based on the database type and
28+
// resides in the a directory named after the network type.
29+
newDbRoot := filepath.Join(filepath.Dir(cfg.DataDir), netName)
30+
newDbName := blockDbNamePrefix + "_" + oldDbType
31+
if oldDbType == "sqlite" {
32+
newDbName = newDbName + ".db"
33+
}
34+
newDbPath := filepath.Join(newDbRoot, newDbName)
35+
36+
// Create the new path if needed.
37+
err = os.MkdirAll(newDbRoot, 0700)
38+
if err != nil {
39+
return err
40+
}
41+
42+
// Move and rename the old database.
43+
err := os.Rename(oldDbPath, newDbPath)
44+
if err != nil {
45+
return err
46+
}
47+
}
48+
49+
return nil
50+
}
51+
52+
// upgradeDBPaths moves the databases from their locations prior to btcd
53+
// version 0.2.0 to their new locations.
54+
func upgradeDBPaths() error {
55+
// Prior to version 0.2.0, the databases were in the "db" directory and
56+
// their names were suffixed by "testnet" and "regtest" for their
57+
// respective networks. Check for the old database and update it to the
58+
// new path introduced with version 0.2.0 accodingly.
59+
oldDbRoot := filepath.Join(btcdHomeDir(), "db")
60+
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd.db"), "mainnet")
61+
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd_testnet.db"), "testnet")
62+
upgradeDBPathNet(filepath.Join(oldDbRoot, "btcd_regtest.db"), "regtest")
63+
64+
// Remove the old db directory.
65+
err := os.RemoveAll(oldDbRoot)
66+
if err != nil {
67+
return err
68+
}
69+
70+
return nil
71+
}
72+
773
// doUpgrades performs upgrades to btcd as new versions require it.
874
func doUpgrades() error {
9-
return nil
75+
return upgradeDBPaths()
1076
}

version.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr
1717
// versioning 2.0.0 spec (http://semver.org/).
1818
const (
1919
appMajor uint = 0
20-
appMinor uint = 1
20+
appMinor uint = 2
2121
appPatch uint = 0
2222

2323
// appPreRelease MUST only contain characters from semanticAlphabet

0 commit comments

Comments
 (0)