1
0
Fork 0
forked from External/grumble

Make hierarchy creation the only mode for blobstore. Cache a 'good' directory structure with a 'blobstore' file in the blobstore directory.

This commit is contained in:
Mikkel Krautz 2011-11-08 15:38:30 +01:00
parent 71b8314c2e
commit 852d1790ae
2 changed files with 35 additions and 31 deletions

View file

@ -19,7 +19,6 @@ import (
type BlobStore struct { type BlobStore struct {
dir string dir string
lockfn string lockfn string
makeall bool
} }
const ( const (
@ -42,7 +41,7 @@ var (
// Open an existing, or create a new BlobStore at path. // Open an existing, or create a new BlobStore at path.
// Path must point to a directory, and must already exist. // Path must point to a directory, and must already exist.
// See NewBlobStore for more information. // See NewBlobStore for more information.
func Open(path string, makeall bool) (err error) { func Open(path string) (err error) {
defaultMutex.Lock() defaultMutex.Lock()
defer defaultMutex.Unlock() defer defaultMutex.Unlock()
@ -50,7 +49,7 @@ func Open(path string, makeall bool) (err error) {
panic("Default BlobStore already open") panic("Default BlobStore already open")
} }
defaultStore, err = NewBlobStore(path, makeall) defaultStore, err = NewBlobStore(path)
return return
} }
@ -84,15 +83,7 @@ func Put(buf []byte) (key string, err error) {
// Open an existing, or create a new BlobStore residing at path. // Open an existing, or create a new BlobStore residing at path.
// Path must point to a directory, and must already exist. // Path must point to a directory, and must already exist.
// func NewBlobStore(path string) (bs *BlobStore, err error) {
// The makeall argument determines whether the BlobStore should
// create all possible blob-container directories a priori.
// This can take up a bit of disk space since the metadata for
// those directories can take up a lot of space. However, tt saves
// some I/O operations when writing blobs. (Since the BlobStore
// knows that all directories will exist, it does not need to check
// whether they do, and create them if they do not.).
func NewBlobStore(path string, makeall bool) (bs *BlobStore, err error) {
// Does the directory exist? // Does the directory exist?
dir, err := os.Open(path) dir, err := os.Open(path)
if err != nil { if err != nil {
@ -115,7 +106,21 @@ func NewBlobStore(path string, makeall bool) (bs *BlobStore, err error) {
} }
}() }()
if makeall { dirStructureExists := true
// Check whether a 'blobstore' file exists in the directory.
// The existence of the file signals that the directory already
// has the correct hierarchy structure.
bsf, err := os.Open(filepath.Join(path, "blobstore"))
if err != nil {
if e, ok := err.(*os.PathError); ok {
if e.Err == os.ENOENT {
dirStructureExists = false
}
}
}
bsf.Close()
if !dirStructureExists {
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
outer := filepath.Join(path, hex.EncodeToString([]byte{byte(i)})) outer := filepath.Join(path, hex.EncodeToString([]byte{byte(i)}))
err = os.Mkdir(outer, 0700) err = os.Mkdir(outer, 0700)
@ -158,12 +163,19 @@ func NewBlobStore(path string, makeall bool) (bs *BlobStore, err error) {
} }
} }
} }
// Add a blobstore file to signal that a correct directory
// structure exists for this blobstore.
bsf, err = os.Create(filepath.Join(path, "blobstore"))
if err != nil {
return nil, err
}
bsf.Close()
} }
bs = &BlobStore{ bs = &BlobStore{
dir: path, dir: path,
lockfn: lockfn, lockfn: lockfn,
makeall: makeall,
} }
return bs, nil return bs, nil
} }
@ -270,14 +282,6 @@ func (bs *BlobStore) Put(buf []byte) (key string, err error) {
} }
} }
if !bs.makeall {
// Make sure the leading directories exist...
err = os.MkdirAll(filepath.ToSlash(blobdir), 0700)
if err != nil {
return
}
}
// Create a temporary file to write to. Once we're done, we // Create a temporary file to write to. Once we're done, we
// can atomically rename the file to the correct key. // can atomically rename the file to the correct key.
file, err = ioutil.TempFile(blobdir, rest) file, err = ioutil.TempFile(blobdir, rest)

View file

@ -22,7 +22,7 @@ func TestMakeAllCreateAll(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
bs, err := NewBlobStore(dir, true) bs, err := NewBlobStore(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -35,7 +35,7 @@ func TestMakeAllCreateAll(t *testing.T) {
dirname := filepath.Join(dir, hex.EncodeToString([]byte{byte(i)}), hex.EncodeToString([]byte{byte(j)})) dirname := filepath.Join(dir, hex.EncodeToString([]byte{byte(i)}), hex.EncodeToString([]byte{byte(j)}))
fi, err := os.Stat(dirname) fi, err := os.Stat(dirname)
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
} }
if !fi.IsDirectory() { if !fi.IsDirectory() {
t.Errorf("Not a directory") t.Errorf("Not a directory")
@ -57,7 +57,7 @@ func TestAllInvalidFiles(t *testing.T) {
t.Error(err) t.Error(err)
} }
_, err = NewBlobStore(dir, true) _, err = NewBlobStore(dir)
if err == ErrBadFile { if err == ErrBadFile {
// Success // Success
} else if err != nil { } else if err != nil {
@ -85,7 +85,7 @@ func TestAllInvalidFilesLevel2(t *testing.T) {
t.Error(err) t.Error(err)
} }
_, err = NewBlobStore(dir, true) _, err = NewBlobStore(dir)
if err == ErrBadFile { if err == ErrBadFile {
// Success // Success
} else if err != nil { } else if err != nil {
@ -103,7 +103,7 @@ func TestStoreRetrieve(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
bs, err := NewBlobStore(dir, false) bs, err := NewBlobStore(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -136,7 +136,7 @@ func TestReadNonExistantKey(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
bs, err := NewBlobStore(dir, false) bs, err := NewBlobStore(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -160,7 +160,7 @@ func TestReadInvalidKeyLength(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
bs, err := NewBlobStore(dir, false) bs, err := NewBlobStore(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -187,7 +187,7 @@ func TestReadInvalidKeyNonHex(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
bs, err := NewBlobStore(dir, false) bs, err := NewBlobStore(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
@ -214,7 +214,7 @@ func TestDefaultBlobStore(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
err = Open(dir, false) err = Open(dir)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }