提交 5027b4b1 作者: Kevin Atkinson 提交者: Jeromy

Implement DiskId()

License: MIT
Signed-off-by: 's avatarKevin Atkinson <k@kevina.org>
上级 1f97170e
...@@ -75,17 +75,28 @@ func TestDefaultDatastoreConfig(t *testing.T) { ...@@ -75,17 +75,28 @@ func TestDefaultDatastoreConfig(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) // clean up defer os.RemoveAll(dir) // clean up
repo := FSRepo{path: dir}
config := new(config.Datastore) config := new(config.Datastore)
err = json.Unmarshal(defaultConfig, config) err = json.Unmarshal(defaultConfig, config)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
ds, err := repo.constructDatastore(config.Spec)
dsc, err := AnyDatastoreConfig(config.Spec)
if err != nil {
t.Fatal(err)
}
expected := "/blocks:{flatfs;blocks;/repo/flatfs/shard/v1/next-to-last/2};/:{levelds;datastore};"
if dsc.DiskId() != expected {
t.Errorf("expected '%s' got '%s' as DiskId", expected, dsc.DiskId())
}
ds, err := dsc.Create(dir)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if typ := reflect.TypeOf(ds).String(); typ != "*syncmount.Datastore" { if typ := reflect.TypeOf(ds).String(); typ != "*syncmount.Datastore" {
t.Errorf("expected '*syncmount.Datastore' got '%s'", typ) t.Errorf("expected '*syncmount.Datastore' got '%s'", typ)
} }
...@@ -102,17 +113,28 @@ func TestLevelDbConfig(t *testing.T) { ...@@ -102,17 +113,28 @@ func TestLevelDbConfig(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) // clean up defer os.RemoveAll(dir) // clean up
repo := FSRepo{path: dir}
spec := make(map[string]interface{}) spec := make(map[string]interface{})
err = json.Unmarshal(leveldbConfig, &spec) err = json.Unmarshal(leveldbConfig, &spec)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
ds, err := repo.constructDatastore(spec)
dsc, err := AnyDatastoreConfig(spec)
if err != nil {
t.Fatal(err)
}
expected := "levelds;datastore"
if dsc.DiskId() != expected {
t.Errorf("expected '%s' got '%s' as DiskId", expected, dsc.DiskId())
}
ds, err := dsc.Create(dir)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if typ := reflect.TypeOf(ds).String(); typ != "*leveldb.datastore" { if typ := reflect.TypeOf(ds).String(); typ != "*leveldb.datastore" {
t.Errorf("expected '*leveldb.datastore' got '%s'", typ) t.Errorf("expected '*leveldb.datastore' got '%s'", typ)
} }
...@@ -129,17 +151,28 @@ func TestFlatfsConfig(t *testing.T) { ...@@ -129,17 +151,28 @@ func TestFlatfsConfig(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) // clean up defer os.RemoveAll(dir) // clean up
repo := FSRepo{path: dir}
spec := make(map[string]interface{}) spec := make(map[string]interface{})
err = json.Unmarshal(flatfsConfig, &spec) err = json.Unmarshal(flatfsConfig, &spec)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
ds, err := repo.constructDatastore(spec)
dsc, err := AnyDatastoreConfig(spec)
if err != nil {
t.Fatal(err)
}
expected := "flatfs;blocks;/repo/flatfs/shard/v1/next-to-last/2"
if dsc.DiskId() != expected {
t.Errorf("expected '%s' got '%s' as DiskId", expected, dsc.DiskId())
}
ds, err := dsc.Create(dir)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if typ := reflect.TypeOf(ds).String(); typ != "*flatfs.Datastore" { if typ := reflect.TypeOf(ds).String(); typ != "*flatfs.Datastore" {
t.Errorf("expected '*flatfs.Datastore' got '%s'", typ) t.Errorf("expected '*flatfs.Datastore' got '%s'", typ)
} }
...@@ -156,17 +189,28 @@ func TestMeasureConfig(t *testing.T) { ...@@ -156,17 +189,28 @@ func TestMeasureConfig(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) // clean up defer os.RemoveAll(dir) // clean up
repo := FSRepo{path: dir}
spec := make(map[string]interface{}) spec := make(map[string]interface{})
err = json.Unmarshal(measureConfig, &spec) err = json.Unmarshal(measureConfig, &spec)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
ds, err := repo.constructDatastore(spec)
dsc, err := AnyDatastoreConfig(spec)
if err != nil {
t.Fatal(err)
}
expected := "flatfs;blocks;/repo/flatfs/shard/v1/next-to-last/2"
if dsc.DiskId() != expected {
t.Errorf("expected '%s' got '%s' as DiskId", expected, dsc.DiskId())
}
ds, err := dsc.Create(dir)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if typ := reflect.TypeOf(ds).String(); typ != "*measure.measure" { if typ := reflect.TypeOf(ds).String(); typ != "*measure.measure" {
t.Errorf("expected '*measure.measure' got '%s'", typ) t.Errorf("expected '*measure.measure' got '%s'", typ)
} }
......
package fsrepo package fsrepo
import ( import (
"bytes"
"fmt" "fmt"
"path/filepath" "path/filepath"
...@@ -18,9 +19,11 @@ import ( ...@@ -18,9 +19,11 @@ import (
type ConfigFromMap func(map[string]interface{}) (DatastoreConfig, error) type ConfigFromMap func(map[string]interface{}) (DatastoreConfig, error)
type DatastoreConfig interface { type DatastoreConfig interface {
// DiskId is a unique id representing the Datastore config as stored on disk, runtime config values are not // DiskId is a unique id representing the Datastore config as
// part of this Id. No length limit. // stored on disk, runtime config values are not part of this Id.
//DiskId() string // Returns an empty string if the datastore does not have an on
// disk representation. No length limit.
DiskId() string
// Create instantiate a new datastore from this config // Create instantiate a new datastore from this config
Create(path string) (repo.Datastore, error) Create(path string) (repo.Datastore, error)
...@@ -91,6 +94,14 @@ func MountDatastoreConfig(params map[string]interface{}) (DatastoreConfig, error ...@@ -91,6 +94,14 @@ func MountDatastoreConfig(params map[string]interface{}) (DatastoreConfig, error
return &res, nil return &res, nil
} }
func (c *mountDatastoreConfig) DiskId() string {
buf := new(bytes.Buffer)
for _, m := range c.mounts {
fmt.Fprintf(buf, "%s:{%s};", m.prefix.String(), m.ds.DiskId())
}
return buf.String()
}
func (c *mountDatastoreConfig) Create(path string) (repo.Datastore, error) { func (c *mountDatastoreConfig) Create(path string) (repo.Datastore, error) {
mounts := make([]mount.Mount, len(c.mounts)) mounts := make([]mount.Mount, len(c.mounts))
for i, m := range c.mounts { for i, m := range c.mounts {
...@@ -136,6 +147,10 @@ func FlatfsDatastoreConfig(params map[string]interface{}) (DatastoreConfig, erro ...@@ -136,6 +147,10 @@ func FlatfsDatastoreConfig(params map[string]interface{}) (DatastoreConfig, erro
return &c, nil return &c, nil
} }
func (c *flatfsDatastoreConfig) DiskId() string {
return fmt.Sprintf("flatfs;%s;%s", c.path, c.shardFun.String())
}
func (c *flatfsDatastoreConfig) Create(path string) (repo.Datastore, error) { func (c *flatfsDatastoreConfig) Create(path string) (repo.Datastore, error) {
p := c.path p := c.path
if !filepath.IsAbs(p) { if !filepath.IsAbs(p) {
...@@ -173,6 +188,10 @@ func LeveldsDatastoreConfig(params map[string]interface{}) (DatastoreConfig, err ...@@ -173,6 +188,10 @@ func LeveldsDatastoreConfig(params map[string]interface{}) (DatastoreConfig, err
return &c, nil return &c, nil
} }
func (c *leveldsDatastoreConfig) DiskId() string {
return fmt.Sprintf("levelds;%s", c.path)
}
func (c *leveldsDatastoreConfig) Create(path string) (repo.Datastore, error) { func (c *leveldsDatastoreConfig) Create(path string) (repo.Datastore, error) {
p := c.path p := c.path
if !filepath.IsAbs(p) { if !filepath.IsAbs(p) {
...@@ -192,6 +211,10 @@ func MemDatastoreConfig(params map[string]interface{}) (DatastoreConfig, error) ...@@ -192,6 +211,10 @@ func MemDatastoreConfig(params map[string]interface{}) (DatastoreConfig, error)
return &memDatastoreConfig{params}, nil return &memDatastoreConfig{params}, nil
} }
func (c *memDatastoreConfig) DiskId() string {
return ""
}
func (c *memDatastoreConfig) Create(string) (repo.Datastore, error) { func (c *memDatastoreConfig) Create(string) (repo.Datastore, error) {
return ds.NewMapDatastore(), nil return ds.NewMapDatastore(), nil
} }
...@@ -226,6 +249,10 @@ func (c *logDatastoreConfig) Create(path string) (repo.Datastore, error) { ...@@ -226,6 +249,10 @@ func (c *logDatastoreConfig) Create(path string) (repo.Datastore, error) {
return ds.NewLogDatastore(child, c.name), nil return ds.NewLogDatastore(child, c.name), nil
} }
func (c *logDatastoreConfig) DiskId() string {
return c.child.DiskId()
}
type measureDatastoreConfig struct { type measureDatastoreConfig struct {
child DatastoreConfig child DatastoreConfig
prefix string prefix string
...@@ -247,6 +274,10 @@ func MeasureDatastoreConfig(params map[string]interface{}) (DatastoreConfig, err ...@@ -247,6 +274,10 @@ func MeasureDatastoreConfig(params map[string]interface{}) (DatastoreConfig, err
return &measureDatastoreConfig{child, prefix}, nil return &measureDatastoreConfig{child, prefix}, nil
} }
func (c *measureDatastoreConfig) DiskId() string {
return c.child.DiskId()
}
func (c measureDatastoreConfig) Create(path string) (repo.Datastore, error) { func (c measureDatastoreConfig) Create(path string) (repo.Datastore, error) {
child, err := c.child.Create(path) child, err := c.child.Create(path)
if err != nil { if err != nil {
......
package fsrepo package fsrepo
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
...@@ -357,18 +358,39 @@ func (r *FSRepo) openKeystore() error { ...@@ -357,18 +358,39 @@ func (r *FSRepo) openKeystore() error {
// openDatastore returns an error if the config file is not present. // openDatastore returns an error if the config file is not present.
func (r *FSRepo) openDatastore() error { func (r *FSRepo) openDatastore() error {
if r.config.Datastore.Spec != nil { if r.config.Datastore.Type != "" || r.config.Datastore.Path != "" {
d, err := r.constructDatastore(r.config.Datastore.Spec) return fmt.Errorf("old style datatstore config detected")
} else if r.config.Datastore.Spec == nil {
return fmt.Errorf("required Datastore.Spec entry missing form config file")
}
dsc, err := AnyDatastoreConfig(r.config.Datastore.Spec)
if err != nil {
return err
}
diskId := dsc.DiskId()
oldDiskId, err := r.readDiskId()
if err == nil {
if oldDiskId != diskId {
return fmt.Errorf("Datastore configuration of '%s' does not match what is on disk '%s'",
oldDiskId, diskId)
}
} else if os.IsNotExist(err) {
err := r.writeDiskId(diskId)
if err != nil { if err != nil {
return err return err
} }
r.ds = d
} else if r.config.Datastore.Type != "" || r.config.Datastore.Path != "" {
return fmt.Errorf("old style datatstore config detected")
} else { } else {
return fmt.Errorf("required Datastore.Spec entry missing form config file") return err
} }
d, err := dsc.Create(r.path)
if err != nil {
return err
}
r.ds = d
// Wrap it with metrics gathering // Wrap it with metrics gathering
prefix := "ipfs.fsrepo.datastore" prefix := "ipfs.fsrepo.datastore"
r.ds = measure.New(prefix, r.ds) r.ds = measure.New(prefix, r.ds)
...@@ -376,12 +398,31 @@ func (r *FSRepo) openDatastore() error { ...@@ -376,12 +398,31 @@ func (r *FSRepo) openDatastore() error {
return nil return nil
} }
func (r *FSRepo) constructDatastore(params map[string]interface{}) (repo.Datastore, error) { var DiskIdFn = "dsid"
cfg, err := AnyDatastoreConfig(params)
func (r *FSRepo) readDiskId() (string, error) {
fn, err := config.Path(r.path, DiskIdFn)
if err != nil { if err != nil {
return nil, err return "", err
}
b, err := ioutil.ReadFile(fn)
if err != nil {
return "", err
}
b = bytes.TrimSpace(b)
return string(b), nil
}
func (r *FSRepo) writeDiskId(newId string) error {
fn, err := config.Path(r.path, DiskIdFn)
if err != nil {
return err
} }
return cfg.Create(r.path) err = ioutil.WriteFile(fn, []byte(newId), 0666)
if err != nil {
return err
}
return nil
} }
// Close closes the FSRepo, releasing held resources. // Close closes the FSRepo, releasing held resources.
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论