Commit 7b9e2c5d authored by Kirill Smelkov's avatar Kirill Smelkov

X zodb: Generalize LoadError -> OpError to be returned by all ZODB operations

parent 5886aad3
...@@ -33,7 +33,6 @@ import ( ...@@ -33,7 +33,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"lab.nexedi.com/kirr/go123/mem" "lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xnet" "lab.nexedi.com/kirr/go123/xnet"
"lab.nexedi.com/kirr/neo/go/neo" "lab.nexedi.com/kirr/neo/go/neo"
...@@ -362,7 +361,11 @@ func (c *Client) initFromMaster(ctx context.Context, mlink *neo.NodeLink) (err e ...@@ -362,7 +361,11 @@ func (c *Client) initFromMaster(ctx context.Context, mlink *neo.NodeLink) (err e
// --- user API calls --- // --- user API calls ---
func (c *Client) LastTid(ctx context.Context) (_ zodb.Tid, err error) { func (c *Client) LastTid(ctx context.Context) (_ zodb.Tid, err error) {
defer xerr.Context(&err, "client: lastTid") defer func() {
if err != nil {
err = &zodb.OpError{URL: c.URL(), Op: "last_tid", Args: nil, Err: err}
}
}()
// XXX or require full withOperational ? // XXX or require full withOperational ?
mlink, err := c.masterLink(ctx) mlink, err := c.masterLink(ctx)
...@@ -389,7 +392,7 @@ func (c *Client) Load(ctx context.Context, xid zodb.Xid) (buf *mem.Buf, serial z ...@@ -389,7 +392,7 @@ func (c *Client) Load(ctx context.Context, xid zodb.Xid) (buf *mem.Buf, serial z
// defer func() ... // defer func() ...
buf, serial, err = c._Load(ctx, xid) buf, serial, err = c._Load(ctx, xid)
if err != nil { if err != nil {
err = &zodb.LoadError{URL: c.URL(), Xid: xid, Err: err} err = &zodb.OpError{URL: c.URL(), Op: "load", Args: xid, Err: err}
} }
return buf, serial, err return buf, serial, err
} }
......
...@@ -515,9 +515,10 @@ func TestMasterStorage(t *testing.T) { ...@@ -515,9 +515,10 @@ func TestMasterStorage(t *testing.T) {
} }
} else { } else {
// deleted // deleted
errWant := &zodb.LoadError{ errWant := &zodb.OpError{
URL: C.URL(), URL: C.URL(),
Xid: xid, Op: "load",
Args: xid,
Err: &zodb.NoDataError{Oid: xid.Oid, DeletedAt: datai.Tid}, Err: &zodb.NoDataError{Oid: xid.Oid, DeletedAt: datai.Tid},
} }
if !(buf == nil && serial == 0 && reflect.DeepEqual(err, errWant)) { if !(buf == nil && serial == 0 && reflect.DeepEqual(err, errWant)) {
......
...@@ -551,7 +551,7 @@ func (stor *Storage) serveClient1(ctx context.Context, req neo.Msg) (resp neo.Ms ...@@ -551,7 +551,7 @@ func (stor *Storage) serveClient1(ctx context.Context, req neo.Msg) (resp neo.Ms
buf, serial, err := stor.zstor.Load(ctx, xid) buf, serial, err := stor.zstor.Load(ctx, xid)
if err != nil { if err != nil {
// translate err to NEO protocol error codes // translate err to NEO protocol error codes
e := err.(*zodb.LoadError) // XXX move this to ErrEncode? e := err.(*zodb.OpError) // XXX move this to ErrEncode?
return neo.ErrEncode(e.Err) return neo.ErrEncode(e.Err)
} }
......
...@@ -169,7 +169,7 @@ func (c *Cache) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, er ...@@ -169,7 +169,7 @@ func (c *Cache) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, er
} }
if rce.err != nil { if rce.err != nil {
return nil, 0, &LoadError{URL: c.loader.URL(), Xid: xid, Err: rce.err} return nil, 0, &OpError{URL: c.loader.URL(), Op: "load", Args: xid, Err: rce.err}
} }
return rce.buf, rce.serial, nil return rce.buf, rce.serial, nil
...@@ -180,6 +180,8 @@ func (c *Cache) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, er ...@@ -180,6 +180,8 @@ func (c *Cache) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, er
// If data is not yet in cache loading for it is started in the background. // If data is not yet in cache loading for it is started in the background.
// Prefetch is not blocking operation and does not wait for loading, if any was // Prefetch is not blocking operation and does not wait for loading, if any was
// started, to complete. // started, to complete.
//
// Prefetch does not return any error.
func (c *Cache) Prefetch(ctx context.Context, xid Xid) { func (c *Cache) Prefetch(ctx context.Context, xid Xid) {
rce, rceNew := c.lookupRCE(xid, +0) rce, rceNew := c.lookupRCE(xid, +0)
...@@ -303,10 +305,11 @@ func (c *Cache) loadRCE(ctx context.Context, rce *revCacheEntry) { ...@@ -303,10 +305,11 @@ func (c *Cache) loadRCE(ctx context.Context, rce *revCacheEntry) {
// normalize buf/serial if it was error // normalize buf/serial if it was error
if err != nil { if err != nil {
e := err.(*LoadError) // XXX better driver return *LoadError explicitly e := err.(*OpError) // XXX better driver return *OpError explicitly
// only remember problem cause - full LoadError will be // only remember problem cause - full OpError will be
// reconstructed in Load with actual requested there xid. // reconstructed in Load with actual requested there xid.
// XXX check .Op == "load" ?
err = e.Err err = e.Err
// TODO err == canceled? -> don't remember // TODO err == canceled? -> don't remember
buf.XRelease() buf.XRelease()
......
...@@ -75,7 +75,7 @@ func (stor *tStorage) Load(_ context.Context, xid Xid) (buf *mem.Buf, serial Tid ...@@ -75,7 +75,7 @@ func (stor *tStorage) Load(_ context.Context, xid Xid) (buf *mem.Buf, serial Tid
//defer func() { fmt.Printf("< %v, %v, %v\n", buf.XData(), serial, err) }() //defer func() { fmt.Printf("< %v, %v, %v\n", buf.XData(), serial, err) }()
buf, serial, err = stor.load(xid) buf, serial, err = stor.load(xid)
if err != nil { if err != nil {
err = &LoadError{URL: stor.URL(), Xid: xid, Err: err} err = &OpError{URL: stor.URL(), Op: "load", Args: xid, Err: err}
} }
return buf, serial, err return buf, serial, err
} }
...@@ -163,7 +163,7 @@ func TestCache(t *testing.T) { ...@@ -163,7 +163,7 @@ func TestCache(t *testing.T) {
var err error var err error
if errCause != nil { if errCause != nil {
err = &LoadError{URL: "test", Xid: xid, Err: errCause} err = &OpError{URL: "test", Op: "load", Args: xid, Err: errCause}
} }
if !reflect.DeepEqual(err, e) { if !reflect.DeepEqual(err, e) {
fmt.Fprintf(bad, "err:\n%s\n", pretty.Compare(err, e)) fmt.Fprintf(bad, "err:\n%s\n", pretty.Compare(err, e))
......
...@@ -105,7 +105,7 @@ type storage struct { ...@@ -105,7 +105,7 @@ type storage struct {
func (s *storage) Load(ctx context.Context, xid Xid) (*mem.Buf, Tid, error) { func (s *storage) Load(ctx context.Context, xid Xid) (*mem.Buf, Tid, error) {
// XXX here: offload xid validation from cache and driver ? // XXX here: offload xid validation from cache and driver ?
// XXX here: offload wrapping err -> LoadError{err} ? // XXX here: offload wrapping err -> OpError{"load", err} ?
return s.l1cache.Load(ctx, xid) return s.l1cache.Load(ctx, xid)
} }
......
...@@ -131,7 +131,7 @@ func (fs *FileStorage) Load(_ context.Context, xid zodb.Xid) (buf *mem.Buf, seri ...@@ -131,7 +131,7 @@ func (fs *FileStorage) Load(_ context.Context, xid zodb.Xid) (buf *mem.Buf, seri
// -> TODO reject tid out of range // -> TODO reject tid out of range
buf, serial, err = fs.load(xid) buf, serial, err = fs.load(xid)
if err != nil { if err != nil {
err = &zodb.LoadError{URL: fs.URL(), Xid: xid, Err: err} err = &zodb.OpError{URL: fs.URL(), Op: "load", Args: xid, Err: err}
} }
return buf, serial, err return buf, serial, err
} }
...@@ -218,6 +218,7 @@ const ( ...@@ -218,6 +218,7 @@ const (
// NextTxn iterates to next/previous transaction record according to iteration direction // NextTxn iterates to next/previous transaction record according to iteration direction
func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator, error) { func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator, error) {
// TODO err -> OpError("iter", tidmin..tidmax)
switch { switch {
case zi.zFlags & zIterEOF != 0: case zi.zFlags & zIterEOF != 0:
return nil, nil, io.EOF return nil, nil, io.EOF
...@@ -245,6 +246,7 @@ func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator, ...@@ -245,6 +246,7 @@ func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator,
// NextData iterates to next data record and loads data content // NextData iterates to next data record and loads data content
func (zi *zIter) NextData(_ context.Context) (*zodb.DataInfo, error) { func (zi *zIter) NextData(_ context.Context) (*zodb.DataInfo, error) {
// TODO err -> OpError("iter", tidmin..tidmax)
err := zi.iter.NextData() err := zi.iter.NextData()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -381,7 +383,14 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.ITxnIterator { ...@@ -381,7 +383,14 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.ITxnIterator {
return ziter return ziter
case err != nil: case err != nil:
return &iterStartError{err} return &iterStartError{&zodb.OpError{
URL: fs.URL(),
Op: "iter",
// XXX (?) add TidRange type which prints as
// "tidmin..tidmax" with omiting ends if it is either 0 or ∞
Args: []zodb.Tid{tidMin, tidMax},
Err: err,
}}
} }
// setup iter from what findTxnRecord found // setup iter from what findTxnRecord found
...@@ -498,7 +507,7 @@ func Open(ctx context.Context, path string) (_ *FileStorage, err error) { ...@@ -498,7 +507,7 @@ func Open(ctx context.Context, path string) (_ *FileStorage, err error) {
func (fs *FileStorage) Close() error { func (fs *FileStorage) Close() error {
err := fs.file.Close() err := fs.file.Close()
if err != nil { if err != nil {
return err return &zodb.OpError{URL: fs.URL(), Op: "close", Args: nil, Err: err}
} }
// TODO if opened !ro -> .saveIndex() // TODO if opened !ro -> .saveIndex()
......
...@@ -70,9 +70,10 @@ func checkLoad(t *testing.T, fs *FileStorage, xid zodb.Xid, expect objState) { ...@@ -70,9 +70,10 @@ func checkLoad(t *testing.T, fs *FileStorage, xid zodb.Xid, expect objState) {
// deleted obj - it should load with "no data" // deleted obj - it should load with "no data"
if expect.data == nil { if expect.data == nil {
errOk := &zodb.LoadError{ errOk := &zodb.OpError{
URL: fs.URL(), URL: fs.URL(),
Xid: xid, Op: "load",
Args: xid,
Err: &zodb.NoDataError{Oid: xid.Oid , DeletedAt: expect.tid}, Err: &zodb.NoDataError{Oid: xid.Oid , DeletedAt: expect.tid},
} }
if !reflect.DeepEqual(err, errOk) { if !reflect.DeepEqual(err, errOk) {
......
...@@ -147,18 +147,24 @@ func (e *NoDataError) Error() string { ...@@ -147,18 +147,24 @@ func (e *NoDataError) Error() string {
} }
} }
// LoadError is the error returned by IStorageDriver.Load // OpError is the error returned by IStorageDriver operations
type LoadError struct { type OpError struct {
URL string URL string // URL of the storage
Xid Xid Op string // operation that failed
Err error Args interface{} // operation arguments, if any
Err error // actual error that occured during the operation
} }
func (e *LoadError) Error() string { func (e *OpError) Error() string {
return fmt.Sprintf("%s: load %s: %v", e.URL, e.Xid, e.Err) s := e.URL + ": " + e.Op
if e.Args != nil {
s += fmt.Sprintf(" %s", e.Args)
}
s += ": " + e.Err.Error()
return s
} }
func (e *LoadError) Cause() error { func (e *OpError) Cause() error {
return e.Err return e.Err
} }
...@@ -204,7 +210,7 @@ type IStorageDriver interface { ...@@ -204,7 +210,7 @@ type IStorageDriver interface {
// - if there is data to load: buf is non-empty, serial indicates // - if there is data to load: buf is non-empty, serial indicates
// transaction which matched xid criteria and err=nil. // transaction which matched xid criteria and err=nil.
// //
// otherwise buf=nil, serial=0 and err is *LoadError with err.Err // otherwise buf=nil, serial=0 and err is *OpError with err.Err
// describing the error cause: // describing the error cause:
// //
// - *NoObjectError if there is no such object in database at all, // - *NoObjectError if there is no such object in database at all,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment