mirror of
https://github.com/ipfs/kubo.git
synced 2025-07-01 02:30:39 +08:00
Merge pull request #3830 from ipfs/golint-2-filestore
Filestore: make golint happy
This commit is contained in:
@ -1,3 +1,10 @@
|
|||||||
|
// Package filestore implements a Blockstore which is able to read certain
|
||||||
|
// blocks of data directly from its original location in the filesystem.
|
||||||
|
//
|
||||||
|
// In a Filestore, object leaves are stored as FilestoreNodes. FilestoreNodes
|
||||||
|
// include a filesystem path and an offset, allowing a Blockstore dealing with
|
||||||
|
// such blocks to avoid storing the whole contents and reading them from their
|
||||||
|
// filesystem location instead.
|
||||||
package filestore
|
package filestore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -14,23 +21,31 @@ import (
|
|||||||
|
|
||||||
var log = logging.Logger("filestore")
|
var log = logging.Logger("filestore")
|
||||||
|
|
||||||
|
// Filestore implements a Blockstore by combining a standard Blockstore
|
||||||
|
// to store regular blocks and a special Blockstore called
|
||||||
|
// FileManager to store blocks which data exists in an external file.
|
||||||
type Filestore struct {
|
type Filestore struct {
|
||||||
fm *FileManager
|
fm *FileManager
|
||||||
bs blockstore.Blockstore
|
bs blockstore.Blockstore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileManager returns the FileManager in Filestore.
|
||||||
func (f *Filestore) FileManager() *FileManager {
|
func (f *Filestore) FileManager() *FileManager {
|
||||||
return f.fm
|
return f.fm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MainBlockstore returns the standard Blockstore in the Filestore.
|
||||||
func (f *Filestore) MainBlockstore() blockstore.Blockstore {
|
func (f *Filestore) MainBlockstore() blockstore.Blockstore {
|
||||||
return f.bs
|
return f.bs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFilestore creates one using the given Blockstore and FileManager.
|
||||||
func NewFilestore(bs blockstore.Blockstore, fm *FileManager) *Filestore {
|
func NewFilestore(bs blockstore.Blockstore, fm *FileManager) *Filestore {
|
||||||
return &Filestore{fm, bs}
|
return &Filestore{fm, bs}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllKeysChan returns a channel from which to read the keys stored in
|
||||||
|
// the blockstore. If the given context is cancelled the channel will be closed.
|
||||||
func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
|
func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
@ -93,6 +108,10 @@ func (f *Filestore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteBlock deletes the block with the given key from the
|
||||||
|
// blockstore. As expected, in the case of FileManager blocks, only the
|
||||||
|
// reference is deleted, not its contents. It may return
|
||||||
|
// ErrNotFound when the block is not stored.
|
||||||
func (f *Filestore) DeleteBlock(c *cid.Cid) error {
|
func (f *Filestore) DeleteBlock(c *cid.Cid) error {
|
||||||
err1 := f.bs.DeleteBlock(c)
|
err1 := f.bs.DeleteBlock(c)
|
||||||
if err1 != nil && err1 != blockstore.ErrNotFound {
|
if err1 != nil && err1 != blockstore.ErrNotFound {
|
||||||
@ -116,6 +135,8 @@ func (f *Filestore) DeleteBlock(c *cid.Cid) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get retrieves the block with the given Cid. It may return
|
||||||
|
// ErrNotFound when the block is not stored.
|
||||||
func (f *Filestore) Get(c *cid.Cid) (blocks.Block, error) {
|
func (f *Filestore) Get(c *cid.Cid) (blocks.Block, error) {
|
||||||
blk, err := f.bs.Get(c)
|
blk, err := f.bs.Get(c)
|
||||||
switch err {
|
switch err {
|
||||||
@ -130,6 +151,8 @@ func (f *Filestore) Get(c *cid.Cid) (blocks.Block, error) {
|
|||||||
return f.fm.Get(c)
|
return f.fm.Get(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has returns true if the block with the given Cid is
|
||||||
|
// stored in the Filestore.
|
||||||
func (f *Filestore) Has(c *cid.Cid) (bool, error) {
|
func (f *Filestore) Has(c *cid.Cid) (bool, error) {
|
||||||
has, err := f.bs.Has(c)
|
has, err := f.bs.Has(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -143,6 +166,10 @@ func (f *Filestore) Has(c *cid.Cid) (bool, error) {
|
|||||||
return f.fm.Has(c)
|
return f.fm.Has(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put stores a block in the Filestore. For blocks of
|
||||||
|
// underlying type FilestoreNode, the operation is
|
||||||
|
// delegated to the FileManager, while the rest of blocks
|
||||||
|
// are handled by the regular blockstore.
|
||||||
func (f *Filestore) Put(b blocks.Block) error {
|
func (f *Filestore) Put(b blocks.Block) error {
|
||||||
has, err := f.Has(b.Cid())
|
has, err := f.Has(b.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -161,6 +188,8 @@ func (f *Filestore) Put(b blocks.Block) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutMany is like Put(), but takes a slice of blocks, allowing
|
||||||
|
// the underlying blockstore to perform batch transactions.
|
||||||
func (f *Filestore) PutMany(bs []blocks.Block) error {
|
func (f *Filestore) PutMany(bs []blocks.Block) error {
|
||||||
var normals []blocks.Block
|
var normals []blocks.Block
|
||||||
var fstores []*posinfo.FilestoreNode
|
var fstores []*posinfo.FilestoreNode
|
||||||
|
@ -20,26 +20,43 @@ import (
|
|||||||
cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
|
cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FilestorePrefix identifies the key prefix for FileManager blocks.
|
||||||
var FilestorePrefix = ds.NewKey("filestore")
|
var FilestorePrefix = ds.NewKey("filestore")
|
||||||
|
|
||||||
|
// FileManager is a blockstore implementation which stores special
|
||||||
|
// blocks FilestoreNode type. These nodes only contain a reference
|
||||||
|
// to the actual location of the block data in the filesystem
|
||||||
|
// (a path and an offset).
|
||||||
type FileManager struct {
|
type FileManager struct {
|
||||||
ds ds.Batching
|
ds ds.Batching
|
||||||
root string
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CorruptReferenceError implements the error interface.
|
||||||
|
// It is used to indicate that the block contents pointed
|
||||||
|
// by the referencing blocks cannot be retrieved (i.e. the
|
||||||
|
// file is not found, or the data changed as it was being read).
|
||||||
type CorruptReferenceError struct {
|
type CorruptReferenceError struct {
|
||||||
Code Status
|
Code Status
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error() returns the error message in the CorruptReferenceError
|
||||||
|
// as a string.
|
||||||
func (c CorruptReferenceError) Error() string {
|
func (c CorruptReferenceError) Error() string {
|
||||||
return c.Err.Error()
|
return c.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFileManager initializes a new file manager with the given
|
||||||
|
// datastore and root. All FilestoreNodes paths are relative to the
|
||||||
|
// root path given here, which is prepended for any operations.
|
||||||
func NewFileManager(ds ds.Batching, root string) *FileManager {
|
func NewFileManager(ds ds.Batching, root string) *FileManager {
|
||||||
return &FileManager{dsns.Wrap(ds, FilestorePrefix), root}
|
return &FileManager{dsns.Wrap(ds, FilestorePrefix), root}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllKeysChan returns a channel from which to read the keys stored in
|
||||||
|
// the FileManager. If the given context is cancelled the channel will be
|
||||||
|
// closed.
|
||||||
func (f *FileManager) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
|
func (f *FileManager) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
|
||||||
q := dsq.Query{KeysOnly: true}
|
q := dsq.Query{KeysOnly: true}
|
||||||
q.Prefix = FilestorePrefix.String()
|
q.Prefix = FilestorePrefix.String()
|
||||||
@ -76,6 +93,8 @@ func (f *FileManager) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error)
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteBlock deletes the reference-block from the underlying
|
||||||
|
// datastore. It does not touch the referenced data.
|
||||||
func (f *FileManager) DeleteBlock(c *cid.Cid) error {
|
func (f *FileManager) DeleteBlock(c *cid.Cid) error {
|
||||||
err := f.ds.Delete(dshelp.CidToDsKey(c))
|
err := f.ds.Delete(dshelp.CidToDsKey(c))
|
||||||
if err == ds.ErrNotFound {
|
if err == ds.ErrNotFound {
|
||||||
@ -84,6 +103,10 @@ func (f *FileManager) DeleteBlock(c *cid.Cid) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get reads a block from the datastore. Reading a block
|
||||||
|
// is done in two steps: the first step retrieves the reference
|
||||||
|
// block from the datastore. The second step uses the stored
|
||||||
|
// path and offsets to read the raw block data directly from disk.
|
||||||
func (f *FileManager) Get(c *cid.Cid) (blocks.Block, error) {
|
func (f *FileManager) Get(c *cid.Cid) (blocks.Block, error) {
|
||||||
dobj, err := f.getDataObj(c)
|
dobj, err := f.getDataObj(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -165,6 +188,8 @@ func (f *FileManager) readDataObj(c *cid.Cid, d *pb.DataObj) ([]byte, error) {
|
|||||||
return outbuf, nil
|
return outbuf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has returns if the FileManager is storing a block reference. It does not
|
||||||
|
// validate the data, nor checks if the reference is valid.
|
||||||
func (f *FileManager) Has(c *cid.Cid) (bool, error) {
|
func (f *FileManager) Has(c *cid.Cid) (bool, error) {
|
||||||
// NOTE: interesting thing to consider. Has doesnt validate the data.
|
// NOTE: interesting thing to consider. Has doesnt validate the data.
|
||||||
// So the data on disk could be invalid, and we could think we have it.
|
// So the data on disk could be invalid, and we could think we have it.
|
||||||
@ -176,6 +201,8 @@ type putter interface {
|
|||||||
Put(ds.Key, interface{}) error
|
Put(ds.Key, interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put adds a new reference block to the FileManager. It does not check
|
||||||
|
// that the reference is valid.
|
||||||
func (f *FileManager) Put(b *posinfo.FilestoreNode) error {
|
func (f *FileManager) Put(b *posinfo.FilestoreNode) error {
|
||||||
return f.putTo(b, f.ds)
|
return f.putTo(b, f.ds)
|
||||||
}
|
}
|
||||||
@ -204,6 +231,8 @@ func (f *FileManager) putTo(b *posinfo.FilestoreNode, to putter) error {
|
|||||||
return to.Put(dshelp.CidToDsKey(b.Cid()), data)
|
return to.Put(dshelp.CidToDsKey(b.Cid()), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PutMany is like Put() but takes a slice of blocks instead,
|
||||||
|
// allowing it to create a batch transaction.
|
||||||
func (f *FileManager) PutMany(bs []*posinfo.FilestoreNode) error {
|
func (f *FileManager) PutMany(bs []*posinfo.FilestoreNode) error {
|
||||||
batch, err := f.ds.Batch()
|
batch, err := f.ds.Batch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,8 +12,11 @@ import (
|
|||||||
cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
|
cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Status is used to identify the state of the block data referenced
|
||||||
|
// by a FilestoreNode. Among other places, it is used by CorruptReferenceError.
|
||||||
type Status int32
|
type Status int32
|
||||||
|
|
||||||
|
// These are the supported Status codes.
|
||||||
const (
|
const (
|
||||||
StatusOk Status = 0
|
StatusOk Status = 0
|
||||||
StatusFileError Status = 10 // Backing File Error
|
StatusFileError Status = 10 // Backing File Error
|
||||||
@ -23,6 +26,7 @@ const (
|
|||||||
StatusKeyNotFound Status = 30
|
StatusKeyNotFound Status = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// String provides a human-readable representation for Status codes.
|
||||||
func (s Status) String() string {
|
func (s Status) String() string {
|
||||||
switch s {
|
switch s {
|
||||||
case StatusOk:
|
case StatusOk:
|
||||||
@ -42,10 +46,16 @@ func (s Status) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format returns the status formatted as a string
|
||||||
|
// with leading 0s.
|
||||||
func (s Status) Format() string {
|
func (s Status) Format() string {
|
||||||
return fmt.Sprintf("%-7s", s.String())
|
return fmt.Sprintf("%-7s", s.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListRes wraps the response of the List*() functions, which
|
||||||
|
// allows to obtain and verify blocks stored by the FileManager
|
||||||
|
// of a Filestore. It includes information about the referenced
|
||||||
|
// block.
|
||||||
type ListRes struct {
|
type ListRes struct {
|
||||||
Status Status
|
Status Status
|
||||||
ErrorMsg string
|
ErrorMsg string
|
||||||
@ -55,6 +65,7 @@ type ListRes struct {
|
|||||||
Size uint64
|
Size uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormatLong returns a human readable string for a ListRes object.
|
||||||
func (r *ListRes) FormatLong() string {
|
func (r *ListRes) FormatLong() string {
|
||||||
switch {
|
switch {
|
||||||
case r.Key == nil:
|
case r.Key == nil:
|
||||||
@ -66,18 +77,34 @@ func (r *ListRes) FormatLong() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List fetches the block with the given key from the Filemanager
|
||||||
|
// of the given Filestore and returns a ListRes object with the information.
|
||||||
|
// List does not verify that the reference is valid or whether the
|
||||||
|
// raw data is accesible. See Verify().
|
||||||
func List(fs *Filestore, key *cid.Cid) *ListRes {
|
func List(fs *Filestore, key *cid.Cid) *ListRes {
|
||||||
return list(fs, false, key)
|
return list(fs, false, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListAll returns a function as an iterator which, once invoked, returns
|
||||||
|
// one by one each block in the Filestore's FileManager.
|
||||||
|
// ListAll does not verify that the references are valid or whether
|
||||||
|
// the raw data is accessible. See VerifyAll().
|
||||||
func ListAll(fs *Filestore) (func() *ListRes, error) {
|
func ListAll(fs *Filestore) (func() *ListRes, error) {
|
||||||
return listAll(fs, false)
|
return listAll(fs, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify fetches the block with the given key from the Filemanager
|
||||||
|
// of the given Filestore and returns a ListRes object with the information.
|
||||||
|
// Verify makes sure that the reference is valid and the block data can be
|
||||||
|
// read.
|
||||||
func Verify(fs *Filestore, key *cid.Cid) *ListRes {
|
func Verify(fs *Filestore, key *cid.Cid) *ListRes {
|
||||||
return list(fs, true, key)
|
return list(fs, true, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyAll returns a function as an iterator which, once invoked,
|
||||||
|
// returns one by one each block in the Filestore's FileManager.
|
||||||
|
// VerifyAll checks that the reference is valid and that the block data
|
||||||
|
// can be read.
|
||||||
func VerifyAll(fs *Filestore) (func() *ListRes, error) {
|
func VerifyAll(fs *Filestore) (func() *ListRes, error) {
|
||||||
return listAll(fs, true)
|
return listAll(fs, true)
|
||||||
}
|
}
|
||||||
@ -150,7 +177,8 @@ func mkListRes(c *cid.Cid, d *pb.DataObj, err error) *ListRes {
|
|||||||
ErrorMsg: errorMsg,
|
ErrorMsg: errorMsg,
|
||||||
Key: c,
|
Key: c,
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return &ListRes{
|
return &ListRes{
|
||||||
Status: status,
|
Status: status,
|
||||||
ErrorMsg: errorMsg,
|
ErrorMsg: errorMsg,
|
||||||
@ -159,5 +187,4 @@ func mkListRes(c *cid.Cid, d *pb.DataObj, err error) *ListRes {
|
|||||||
Size: *d.Size_,
|
Size: *d.Size_,
|
||||||
Offset: *d.Offset,
|
Offset: *d.Offset,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user