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 (
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xnet"
"lab.nexedi.com/kirr/neo/go/neo"
......@@ -362,7 +361,11 @@ func (c *Client) initFromMaster(ctx context.Context, mlink *neo.NodeLink) (err e
// --- user API calls ---
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 ?
mlink, err := c.masterLink(ctx)
......@@ -389,7 +392,7 @@ func (c *Client) Load(ctx context.Context, xid zodb.Xid) (buf *mem.Buf, serial z
// defer func() ...
buf, serial, err = c._Load(ctx, xid)
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
}
......
......@@ -515,10 +515,11 @@ func TestMasterStorage(t *testing.T) {
}
} else {
// deleted
errWant := &zodb.LoadError{
URL: C.URL(),
Xid: xid,
Err: &zodb.NoDataError{Oid: xid.Oid, DeletedAt: datai.Tid},
errWant := &zodb.OpError{
URL: C.URL(),
Op: "load",
Args: xid,
Err: &zodb.NoDataError{Oid: xid.Oid, DeletedAt: datai.Tid},
}
if !(buf == nil && serial == 0 && reflect.DeepEqual(err, errWant)) {
t.Fatalf("load: %v ->\nbuf:\n%s\nserial:\n%s\nerr:\n%s\n", xid,
......
......@@ -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)
if err != nil {
// 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)
}
......
......@@ -169,7 +169,7 @@ func (c *Cache) Load(ctx context.Context, xid Xid) (buf *mem.Buf, serial Tid, er
}
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
......@@ -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.
// Prefetch is not blocking operation and does not wait for loading, if any was
// started, to complete.
//
// Prefetch does not return any error.
func (c *Cache) Prefetch(ctx context.Context, xid Xid) {
rce, rceNew := c.lookupRCE(xid, +0)
......@@ -303,10 +305,11 @@ func (c *Cache) loadRCE(ctx context.Context, rce *revCacheEntry) {
// normalize buf/serial if it was error
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.
// XXX check .Op == "load" ?
err = e.Err
// TODO err == canceled? -> don't remember
buf.XRelease()
......
......@@ -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) }()
buf, serial, err = stor.load(xid)
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
}
......@@ -163,7 +163,7 @@ func TestCache(t *testing.T) {
var err error
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) {
fmt.Fprintf(bad, "err:\n%s\n", pretty.Compare(err, e))
......
......@@ -105,7 +105,7 @@ type storage struct {
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 wrapping err -> LoadError{err} ?
// XXX here: offload wrapping err -> OpError{"load", err} ?
return s.l1cache.Load(ctx, xid)
}
......
......@@ -131,7 +131,7 @@ func (fs *FileStorage) Load(_ context.Context, xid zodb.Xid) (buf *mem.Buf, seri
// -> TODO reject tid out of range
buf, serial, err = fs.load(xid)
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
}
......@@ -218,6 +218,7 @@ const (
// NextTxn iterates to next/previous transaction record according to iteration direction
func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator, error) {
// TODO err -> OpError("iter", tidmin..tidmax)
switch {
case zi.zFlags & zIterEOF != 0:
return nil, nil, io.EOF
......@@ -245,6 +246,7 @@ func (zi *zIter) NextTxn(_ context.Context) (*zodb.TxnInfo, zodb.IDataIterator,
// NextData iterates to next data record and loads data content
func (zi *zIter) NextData(_ context.Context) (*zodb.DataInfo, error) {
// TODO err -> OpError("iter", tidmin..tidmax)
err := zi.iter.NextData()
if err != nil {
return nil, err
......@@ -381,7 +383,14 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.ITxnIterator {
return ziter
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
......@@ -498,7 +507,7 @@ func Open(ctx context.Context, path string) (_ *FileStorage, err error) {
func (fs *FileStorage) Close() error {
err := fs.file.Close()
if err != nil {
return err
return &zodb.OpError{URL: fs.URL(), Op: "close", Args: nil, Err: err}
}
// TODO if opened !ro -> .saveIndex()
......
......@@ -70,10 +70,11 @@ func checkLoad(t *testing.T, fs *FileStorage, xid zodb.Xid, expect objState) {
// deleted obj - it should load with "no data"
if expect.data == nil {
errOk := &zodb.LoadError{
URL: fs.URL(),
Xid: xid,
Err: &zodb.NoDataError{Oid: xid.Oid , DeletedAt: expect.tid},
errOk := &zodb.OpError{
URL: fs.URL(),
Op: "load",
Args: xid,
Err: &zodb.NoDataError{Oid: xid.Oid , DeletedAt: expect.tid},
}
if !reflect.DeepEqual(err, errOk) {
t.Errorf("load %v: returned err unexpected: %v ; want: %v", xid, err, errOk)
......
......@@ -147,18 +147,24 @@ func (e *NoDataError) Error() string {
}
}
// LoadError is the error returned by IStorageDriver.Load
type LoadError struct {
URL string
Xid Xid
Err error
// OpError is the error returned by IStorageDriver operations
type OpError struct {
URL string // URL of the storage
Op string // operation that failed
Args interface{} // operation arguments, if any
Err error // actual error that occured during the operation
}
func (e *LoadError) Error() string {
return fmt.Sprintf("%s: load %s: %v", e.URL, e.Xid, e.Err)
func (e *OpError) Error() string {
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
}
......@@ -204,7 +210,7 @@ type IStorageDriver interface {
// - if there is data to load: buf is non-empty, serial indicates
// 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:
//
// - *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