Commit 5bb19440 authored by Kirill Smelkov's avatar Kirill Smelkov

X draftly finished catobj

parent 2055fb37
...@@ -70,7 +70,7 @@ func (c *Client) LastTid() (zodb.Tid, error) { ...@@ -70,7 +70,7 @@ func (c *Client) LastTid() (zodb.Tid, error) {
} }
func (c *Client) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error) { func (c *Client) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error) {
panic("TODO") panic("TODO") // XXX
} }
func (c *Client) Iterate(tidMin, tidMax zodb.Tid) zodb.IStorageIterator { func (c *Client) Iterate(tidMin, tidMax zodb.Tid) zodb.IStorageIterator {
......
...@@ -637,6 +637,7 @@ func (dh *DataHeader) loadNext(r io.ReaderAt /* *os.File */, txnh *TxnHeader) er ...@@ -637,6 +637,7 @@ func (dh *DataHeader) loadNext(r io.ReaderAt /* *os.File */, txnh *TxnHeader) er
// LoadData loads data for the data record taking backpointers into account // LoadData loads data for the data record taking backpointers into account
// Data is loaded into *buf, which, if needed, is reallocated to hold all loading data size XXX // Data is loaded into *buf, which, if needed, is reallocated to hold all loading data size XXX
// NOTE on success dh state is changed to data header of original data transaction // NOTE on success dh state is changed to data header of original data transaction
// NOTE "deleted" records are indicated via returning *buf=nil
// TODO buf -> slab // TODO buf -> slab
func (dh *DataHeader) LoadData(r io.ReaderAt /* *os.File */, buf *[]byte) error { func (dh *DataHeader) LoadData(r io.ReaderAt /* *os.File */, buf *[]byte) error {
// scan via backpointers // scan via backpointers
...@@ -737,10 +738,10 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error) ...@@ -737,10 +738,10 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error)
// lookup in index position of oid data record within latest transaction who changed this oid // lookup in index position of oid data record within latest transaction who changed this oid
dataPos, ok := fs.index.Get(xid.Oid) dataPos, ok := fs.index.Get(xid.Oid)
if !ok { if !ok {
// XXX drop oid from ErrOidMissing ? return nil, zodb.Tid(0), &zodb.ErrOidMissing{Oid: xid.Oid}
return nil, zodb.Tid(0), &ErrXidLoad{xid, zodb.ErrOidMissing{Oid: xid.Oid}}
} }
// FIXME zodb.TidMax is only 7fff... tid from outside can be ffff...
dh := DataHeader{Oid: xid.Oid, Tid: zodb.TidMax, PrevRevPos: dataPos} dh := DataHeader{Oid: xid.Oid, Tid: zodb.TidMax, PrevRevPos: dataPos}
tidBefore := xid.XTid.Tid tidBefore := xid.XTid.Tid
if !xid.XTid.TidBefore { if !xid.XTid.TidBefore {
...@@ -754,15 +755,17 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error) ...@@ -754,15 +755,17 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error)
if err == io.EOF { if err == io.EOF {
// no such oid revision // no such oid revision
err = &zodb.ErrXidMissing{Xid: xid} err = &zodb.ErrXidMissing{Xid: xid}
} else {
err = &ErrXidLoad{xid, err}
} }
return nil, zodb.Tid(0), &ErrXidLoad{xid, err}
return nil, zodb.Tid(0), err
} }
} }
// found dh.Tid < tidBefore; check it really satisfies xid.XTid // found dh.Tid < tidBefore; check it really satisfies xid.XTid
if !xid.XTid.TidBefore && dh.Tid != xid.XTid.Tid { if !xid.XTid.TidBefore && dh.Tid != xid.XTid.Tid {
// XXX unify with ^^^ return nil, zodb.Tid(0), &zodb.ErrXidMissing{Xid: xid}
return nil, zodb.Tid(0), &ErrXidLoad{xid, &zodb.ErrXidMissing{Xid: xid}}
} }
// even if we will scan back via backpointers, the tid returned should // even if we will scan back via backpointers, the tid returned should
...@@ -774,6 +777,11 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error) ...@@ -774,6 +777,11 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error)
if err != nil { if err != nil {
return nil, zodb.Tid(0), &ErrXidLoad{xid, err} return nil, zodb.Tid(0), &ErrXidLoad{xid, err}
} }
if data == nil {
// data was deleted
// XXX or allow this and return via data=nil ?
return nil, zodb.Tid(0), &zodb.ErrXidMissing{Xid: xid}
}
return data, tid, nil return data, tid, nil
} }
......
...@@ -62,6 +62,8 @@ func (tid Tid) Valid() bool { ...@@ -62,6 +62,8 @@ func (tid Tid) Valid() bool {
// ---------------------------------------- // ----------------------------------------
// ErrOidMissing is an error which tells that there is no such oid in the database at all // ErrOidMissing is an error which tells that there is no such oid in the database at all
// XXX do we need distinction in between ErrOidMissing & ErrXidMissing ?
// (think how client should handle error from Load ?)
type ErrOidMissing struct { type ErrOidMissing struct {
Oid Oid Oid Oid
} }
...@@ -140,6 +142,7 @@ type IStorage interface { ...@@ -140,6 +142,7 @@ type IStorage interface {
// LoadSerial and LoadBefore generalized into 1 Load (see Xid for details) // LoadSerial and LoadBefore generalized into 1 Load (see Xid for details)
// TODO data []byte -> something allocated from slab ? // TODO data []byte -> something allocated from slab ?
// XXX currently deleted data is returned as data=nil -- is it ok?
Load(xid Xid) (data []byte, tid Tid, err error) // XXX -> StorageRecordInformation ? Load(xid Xid) (data []byte, tid Tid, err error) // XXX -> StorageRecordInformation ?
// -> Prefetch(xid Xid) ... // -> Prefetch(xid Xid) ...
......
...@@ -28,8 +28,21 @@ import ( ...@@ -28,8 +28,21 @@ import (
"../../zodb" "../../zodb"
) )
// Catobj dumps content of one ZODB object XXX text
// Catobj dumps content of one ZODB object
// The object is printed in raw form without any headers (see Dumpobj)
func Catobj(w io.Writer, stor zodb.IStorage, xid zodb.Xid) error { func Catobj(w io.Writer, stor zodb.IStorage, xid zodb.Xid) error {
data, _, err := stor.Load(xid)
if err != nil {
return err
}
_, err = w.Write(data) // NOTE delted data are returned as err by Load
return err // XXX err ctx ?
}
// Dumpobj dumps content of one ZODB object with zodbdump-like header
func Dumpobj(w io.Writer, stor zodb.IStorage, xid zodb.Xid, hashOnly bool) error {
var objInfo zodb.StorageRecordInformation var objInfo zodb.StorageRecordInformation
data, tid, err := stor.Load(xid) data, tid, err := stor.Load(xid)
...@@ -37,13 +50,13 @@ func Catobj(w io.Writer, stor zodb.IStorage, xid zodb.Xid) error { ...@@ -37,13 +50,13 @@ func Catobj(w io.Writer, stor zodb.IStorage, xid zodb.Xid) error {
return err return err
} }
// XXX hack - rework IStorage.Load to fill-in objInfo directly // XXX hack - TODO rework IStorage.Load to fill-in objInfo directly
objInfo.Oid = xid.Oid objInfo.Oid = xid.Oid
objInfo.Tid = tid objInfo.Tid = tid
objInfo.Data = data objInfo.Data = data
objInfo.DataTid = tid // XXX wrong objInfo.DataTid = tid // XXX generally wrong
d := dumper{W: w} // XXX HashOnly + raw dump d := dumper{W: w, HashOnly: hashOnly}
err = d.DumpData(&objInfo) err = d.DumpData(&objInfo)
return err return err
} }
...@@ -62,14 +75,20 @@ xid is object address (see 'zodb help xid'). ...@@ -62,14 +75,20 @@ xid is object address (see 'zodb help xid').
Options: Options:
-h --help this help text. -h --help this help text.
// -hashonly dump only hashes of objects without content. XXX -hashonly dump only hashes of objects without content.
-raw dump object data without any headers. Only one object allowed.
`) `)
} }
func catobjMain(argv []string) { func catobjMain(argv []string) {
hashOnly := false
raw := false
flags := flag.FlagSet{Usage: func() { catobjUsage(os.Stderr) }} flags := flag.FlagSet{Usage: func() { catobjUsage(os.Stderr) }}
flags.Init("", flag.ExitOnError) flags.Init("", flag.ExitOnError)
// flags.BoolVar(&hashOnly, "hashonly", hashOnly, "dump only hashes of objects") flags.BoolVar(&hashOnly, "hashonly", hashOnly, "dump only hashes of objects")
flags.BoolVar(&raw, "raw", hashOnly, "dump object data without any headers. Only one object allowed.")
// TODO also -batch to serve objects a-la `git cat-file --batch` ?
flags.Parse(argv[1:]) flags.Parse(argv[1:])
argv = flags.Args() argv = flags.Args()
...@@ -79,6 +98,10 @@ func catobjMain(argv []string) { ...@@ -79,6 +98,10 @@ func catobjMain(argv []string) {
} }
storUrl := argv[0] storUrl := argv[0]
if hashOnly && raw {
log.Fatal("-hashonly & -raw are incompatible")
}
xidv := []zodb.Xid{} xidv := []zodb.Xid{}
for _, arg := range argv[1:] { for _, arg := range argv[1:] {
xid, err := zodb.ParseXid(arg) xid, err := zodb.ParseXid(arg)
...@@ -89,14 +112,26 @@ func catobjMain(argv []string) { ...@@ -89,14 +112,26 @@ func catobjMain(argv []string) {
xidv = append(xidv, xid) xidv = append(xidv, xid)
} }
if raw && len(xidv) > 1 {
log.Fatal("only 1 object allowed with -raw")
}
stor, err := zodb.OpenStorageURL(storUrl) // TODO read-only stor, err := zodb.OpenStorageURL(storUrl) // TODO read-only
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// TODO defer stor.Close() // TODO defer stor.Close()
catobj := func(xid zodb.Xid) error {
if raw {
return Catobj(os.Stdout, stor, xid)
} else {
return Dumpobj(os.Stdout, stor, xid, hashOnly)
}
}
for _, xid := range xidv { for _, xid := range xidv {
err = Catobj(os.Stdout, stor, xid) err = catobj(xid)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
......
...@@ -66,11 +66,16 @@ Please see zodburi documentation for full details: ...@@ -66,11 +66,16 @@ Please see zodburi documentation for full details:
http://docs.pylonsproject.org/projects/zodburi/ http://docs.pylonsproject.org/projects/zodburi/
` `
var HelpTopics = HelpRegistry{ const helpXid =
{"zurl", "specifying database URL", helpZURL}, `TODO describe
}
=tid:oid
// TODO xid <tid:oid
`
// TODO dump format // TODO dump format
var HelpTopics = HelpRegistry{
{"zurl", "specifying database URL", helpZURL},
{"xid", "specifying object address", helpXid},
}
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