Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
neoppod
Commits
b04cd609
Commit
b04cd609
authored
Jul 24, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
517db5de
Changes
5
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1397 additions
and
63 deletions
+1397
-63
go/zodb/storage/fs1/filestorage.go
go/zodb/storage/fs1/filestorage.go
+113
-63
go/zodb/storage/fs1/fs1tools/dump_test.go
go/zodb/storage/fs1/fs1tools/dump_test.go
+23
-0
go/zodb/storage/fs1/fs1tools/testdata/1.fsdump.ok
go/zodb/storage/fs1/fs1tools/testdata/1.fsdump.ok
+186
-0
go/zodb/storage/fs1/fs1tools/testdata/1.fsdumpv.ok
go/zodb/storage/fs1/fs1tools/testdata/1.fsdumpv.ok
+1074
-0
go/zodb/zodb.go
go/zodb/zodb.go
+1
-0
No files found.
go/zodb/storage/fs1/filestorage.go
View file @
b04cd609
...
...
@@ -892,8 +892,74 @@ func (fs *FileStorage) Load(xid zodb.Xid) (data []byte, tid zodb.Tid, err error)
return
data
,
tid
,
nil
}
// --- raw iteration ---
// TxnIter is iterator over transaction records
type
TxnIter
struct
{
fsSeq
*
xbufio
.
SeqReaderAt
Txnh
TxnHeader
// current transaction record information
Flags
iterFlags
// XXX iterate forward (> 0) / backward (< 0) / EOF reached (== 0)
}
// DataIter is iterator over data records inside one transaction
type
DataIter
struct
{
fsSeq
*
xbufio
.
SeqReaderAt
Txnh
*
TxnHeader
// header of transaction we are iterating inside
Datah
DataHeader
// current data record information
}
// Iter is combined 2-level iterator over transaction and data records
type
Iter
struct
{
TxnIter
DataIter
}
// NextTxn iterates to next/previous transaction record according to iteration direction
func
(
ti
*
TxnIter
)
NextTxn
(
flags
TxnLoadFlags
)
error
{
var
err
error
if
ti
.
Flags
&
iterDir
!=
0
{
err
=
ti
.
Txnh
.
LoadNext
(
ti
.
fsSeq
,
flags
)
}
else
{
err
=
ti
.
Txnh
.
LoadPrev
(
ti
.
fsSeq
,
flags
)
}
//fmt.Println("loaded:", ti.Txnh.Tid)
return
err
}
// NextData iterates to next data record header
func
(
di
*
DataIter
)
NextData
()
error
{
return
di
.
Datah
.
LoadNext
(
di
.
fsSeq
,
di
.
Txnh
)
}
// NextTxn iterates to next transaction record and resets data iterator to iterate inside it
func
(
iter
*
Iter
)
NextTxn
()
error
{
err
:=
iter
.
TxnIter
.
NextTxn
()
if
err
!=
nil
{
return
err
}
// set .DataIter to iterate over .TxnIter.Txnh
iter
.
DataIter
.
Datah
.
Pos
=
fsi
.
txnIter
.
Txnh
.
DataPos
()
iter
.
DataIter
.
Datah
.
DataLen
=
-
DataHeaderSize
// first iteration will go to first data record
}
// IterateRaw ... XXX
func
(
fs
*
FileStorage
)
IterateRaw
(
dir
/*XXX fwd/back*/
)
*
Iter
{
// when iterating use IO optimized for sequential access
fsSeq
:=
xbufio
.
NewSeqReaderAt
(
fs
.
file
)
// XXX setup .TxnIter.dir and start
iter
.
TxnIter
.
fsSeq
=
fsSeq
iter
.
DataIter
.
fsSeq
=
fsSeq
iter
.
DataIter
.
Txnh
=
&
iter
.
txnIter
.
Txnh
return
iter
}
// zodb.IStorage iteration
// --- zodb.IStorage iteration ---
type
iterFlags
int
const
(
...
...
@@ -902,61 +968,41 @@ const (
iterPreloaded
// data for this iteration was already preloaded
)
//
txnIter is iterator over transaction records
type
txn
Iter
struct
{
fsSeq
*
xbufio
.
SeqReaderAt
//
zIter is transaction/data-records iterator as specified by zodb.IStorage
type
z
Iter
struct
{
iter
Iter
Txnh
TxnHeader
// current transaction information
TidStop
zodb
.
Tid
// iterate up to tid <= tidStop | tid >= tidStop depending on .dir
Flags
iterFlags
// iterate forward (> 0) / backward (< 0) / EOF reached (== 0)
}
// dataIter is iterator over data records inside one transaction
type
dataIter
struct
{
fsSeq
*
xbufio
.
SeqReaderAt
Txnh
*
TxnHeader
// header of transaction we are iterating inside
Datah
DataHeader
Flags
iterFlags
// data header for data loading
// XXX need to use separate dh because x.LoadData() changes x state while going through backpointers.
// XXX here to avoid allocations
// ( NOTE: need to use separate dh because x.LoadData() changes x state
// while going through backpointers.
//
// here to avoid allocations )
dhLoading
DataHeader
sri
zodb
.
StorageRecordInformation
// ptr to this will be returned by NextData
dataBuf
[]
byte
}
// iterator is transaction/data-records iterator as specified by zodb.IStorage
type
iterator
struct
{
txnIter
txnIter
dataIter
dataIter
}
func
(
ti
*
txnIter
)
NextTxn
(
flags
TxnLoadFlags
)
error
{
// NextTxn iterates to next/previous transaction record according to iteration direction
func
(
zi
*
zIter
)
NextTxn
()
(
*
zodb
.
TxnInfo
,
zodb
.
IStorageRecordIterator
,
error
)
{
switch
{
case
ti
.
Flags
&
iterEOF
!=
0
:
//println("already eof")
return
io
.
EOF
// XXX needed?
case
ti
.
Flags
&
iterPreloaded
!=
0
:
// first element is already there - preloaded by who initialized
t
xnIter
// first element is already there - preloaded by who initialized
T
xnIter
ti
.
Flags
&=
^
iterPreloaded
//fmt.Println("preloaded:", ti.Txnh.Tid)
default
:
var
err
error
if
ti
.
Flags
&
iterDir
!=
0
{
err
=
ti
.
Txnh
.
LoadNext
(
ti
.
fsSeq
,
flags
)
}
else
{
err
=
ti
.
Txnh
.
LoadPrev
(
ti
.
fsSeq
,
flags
)
}
err
:=
zi
.
iter
.
NextTxn
(
LoadAll
)
// XXX EOF ^^^ is not expected (range pre-cut to valid tids) ?
//fmt.Println("loaded:", ti.Txnh.Tid)
if
err
!=
nil
{
return
err
}
...
...
@@ -970,48 +1016,51 @@ func (ti *txnIter) NextTxn(flags TxnLoadFlags) error {
return
io
.
EOF
}
return
nil
return
&
zi
.
iter
.
Txnh
.
TxnInfo
,
zi
,
nil
}
func
(
di
*
dataIter
)
NextData
()
(
*
zodb
.
StorageRecordInformation
,
error
)
{
err
:=
di
.
Datah
.
LoadNext
(
di
.
fsSeq
,
di
.
Txnh
)
// NextData iterates to next data record and loads data content
func
(
zi
*
zIter
)
NextData
()
(
*
zodb
.
StorageRecordInformation
,
error
)
{
err
:=
zi
.
iter
.
NextData
()
if
err
!=
nil
{
return
nil
,
err
// XXX recheck
}
di
.
sri
.
Oid
=
di
.
Datah
.
Oid
di
.
sri
.
Tid
=
di
.
Datah
.
Tid
zi
.
sri
.
Oid
=
zi
.
iter
.
Datah
.
Oid
zi
.
sri
.
Tid
=
zi
.
iter
.
Datah
.
Tid
// NOTE dh.LoadData() changes dh state while going through backpointers -
// - need to use separate dh because of this
di
.
dhLoading
=
di
.
Datah
di
.
sri
.
Data
=
d
i
.
dataBuf
err
=
di
.
dhLoading
.
LoadData
(
di
.
fsSeq
,
&
d
i
.
sri
.
Data
)
zi
.
dhLoading
=
zi
.
iter
.
Datah
zi
.
sri
.
Data
=
z
i
.
dataBuf
err
=
zi
.
dhLoading
.
LoadData
(
zi
.
iter
.
DataIter
.
fsSeq
,
&
z
i
.
sri
.
Data
)
if
err
!=
nil
{
return
nil
,
err
// XXX recheck
}
// if memory was reallocated - use it next time
if
cap
(
di
.
sri
.
Data
)
>
cap
(
d
i
.
dataBuf
)
{
di
.
dataBuf
=
d
i
.
sri
.
Data
if
cap
(
zi
.
sri
.
Data
)
>
cap
(
z
i
.
dataBuf
)
{
zi
.
dataBuf
=
z
i
.
sri
.
Data
}
di
.
sri
.
DataTid
=
d
i
.
dhLoading
.
Tid
return
&
d
i
.
sri
,
nil
zi
.
sri
.
DataTid
=
z
i
.
dhLoading
.
Tid
return
&
z
i
.
sri
,
nil
}
func
(
fsi
*
iterator
)
NextTxn
()
(
*
zodb
.
TxnInfo
,
zodb
.
IStorageRecordIterator
,
error
)
{
err
:=
fsi
.
txnIter
.
NextTxn
(
LoadAll
)
if
err
!=
nil
{
return
nil
,
nil
,
err
// XXX recheck
}
// set .dataIter to iterate over .txnIter.Txnh
fsi
.
dataIter
.
Datah
.
Pos
=
fsi
.
txnIter
.
Txnh
.
DataPos
()
fsi
.
dataIter
.
Datah
.
DataLen
=
-
DataHeaderSize
// first iteration will go to first data record
return
&
fsi
.
txnIter
.
Txnh
.
TxnInfo
,
&
fsi
.
dataIter
,
nil
// iterStartError is the iterator created when there are preparatory errors
// this way we offload clients, besides handling NextTxn errors, from also
// handling error cases from Iterate.
//
// XXX bad idea? (e.g. it will prevent from devirtualizing what Iterate returns)
type
iterStartError
struct
{
err
error
}
func
(
e
*
iterStartError
)
NextTxn
(
*
zodb
.
TxnInfo
,
zodb
.
IStorageIterator
,
error
)
{
return
nil
,
nil
,
e
.
err
}
func
(
fs
*
FileStorage
)
Iterate
(
tidMin
,
tidMax
zodb
.
Tid
)
zodb
.
IStorageIterator
{
...
...
@@ -1024,14 +1073,15 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.IStorageIterator {
tidMax
=
fs
.
txnhMax
.
Tid
}
// XXX naming
Iter
:=
iterator
{
}
// XXX naming
-> ziter?
ziter
:=
&
zIter
{
iter
}
// when iterating use IO optimized for sequential access
// XXX -> IterateRaw
fsSeq
:=
xbufio
.
NewSeqReaderAt
(
fs
.
file
)
I
ter
.
txnIter
.
fsSeq
=
fsSeq
I
ter
.
dataIter
.
fsSeq
=
fsSeq
Iter
.
dataIter
.
Txnh
=
&
I
ter
.
txnIter
.
Txnh
i
ter
.
txnIter
.
fsSeq
=
fsSeq
i
ter
.
dataIter
.
fsSeq
=
fsSeq
iter
.
dataIter
.
Txnh
=
&
i
ter
.
txnIter
.
Txnh
if
tidMin
>
tidMax
{
Iter
.
txnIter
.
Flags
|=
iterEOF
// empty
...
...
@@ -1065,7 +1115,7 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.IStorageIterator {
}
if
err
!=
nil
{
panic
(
err
)
// XXX
return
&
iterStartError
{
err
}
// XXX err ctx
}
//fmt.Printf("tidRange: %v..%v -> found %v @%v\n", tidMin, tidMax, iter.Txnh.Tid, iter.Txnh.Pos)
...
...
@@ -1075,9 +1125,9 @@ func (fs *FileStorage) Iterate(tidMin, tidMax zodb.Tid) zodb.IStorageIterator {
iter
.
Flags
&=
^
iterEOF
if
iter
.
Flags
&
iterDir
!=
0
{
// when ^^^ we were searching forward first txn was already found
err
=
iter
.
Txnh
.
loadStrings
(
fs
.
file
)
// XXX ok? XXX -> move NextTxn() ?
err
=
iter
.
Txnh
.
loadStrings
(
fs
Seq
)
// XXX ok? XXX -> move NextTxn() ?
if
err
!=
nil
{
panic
(
err
)
// XXX
return
&
iterStartError
{
err
}
}
iter
.
Flags
|=
iterPreloaded
}
...
...
go/zodb/storage/fs1/fs1tools/dump_test.go
0 → 100644
View file @
b04cd609
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
fs1tools
//go:generate sh -c "python2 -c 'from ZODB.FileStorage import fsdump; fsdump.main()' ../testdata/1.fs >testdata/1.fsdump.ok"
//go:generate sh -c "python2 -c 'from ZODB.FileStorage.fsdump import Dumper; import sys; d = Dumper(sys.argv[1]); d.dump()' ../testdata/1.fs >testdata/1.fsdumpv.ok"
go/zodb/storage/fs1/fs1tools/testdata/1.fsdump.ok
0 → 100644
View file @
b04cd609
This diff is collapsed.
Click to expand it.
go/zodb/storage/fs1/fs1tools/testdata/1.fsdumpv.ok
0 → 100644
View file @
b04cd609
This diff is collapsed.
Click to expand it.
go/zodb/zodb.go
View file @
b04cd609
...
...
@@ -165,6 +165,7 @@ type IStorage interface {
// tpc_finish(txn, callback) XXX clarify about callback
// tpc_abort(txn)
// XXX text
Iterate
(
tidMin
,
tidMax
Tid
)
IStorageIterator
// XXX , error ?
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment