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
03cfbf7e
Commit
03cfbf7e
authored
7 years ago
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
1f98a716
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
101 additions
and
29 deletions
+101
-29
t/neo/storage/fs1/xbufio.go
t/neo/storage/fs1/xbufio.go
+59
-11
t/neo/storage/fs1/xbufio_test.go
t/neo/storage/fs1/xbufio_test.go
+42
-18
No files found.
t/neo/storage/fs1/xbufio.go
View file @
03cfbf7e
...
...
@@ -33,6 +33,7 @@ import (
// SeqBufReader implements buffering for a io.ReaderAt optimized for sequential access
// Both forward, backward and interleaved forward/backward access patterns are supported XXX
// FIXME access from multiple goroutines? (it is required per io.ReaderAt
// interface, but for sequential workloads we do not need it)
// XXX -> xbufio.SeqReader
...
...
@@ -41,8 +42,13 @@ type SeqBufReader struct {
buf
[]
byte
pos
int64
// position of last IO (can be != .pos because large reads are not buffered)
posLastIO
int64
// // position of last IO (can be != .pos because large reads are not buffered)
// posLastIO int64
// TODO text
posLastAccess
int64
posLastFwdAfter
int64
posLastBackward
int64
r
io
.
ReaderAt
}
...
...
@@ -55,7 +61,7 @@ func NewSeqBufReader(r io.ReaderAt) *SeqBufReader {
}
func
NewSeqBufReaderSize
(
r
io
.
ReaderAt
,
size
int
)
*
SeqBufReader
{
sb
:=
&
SeqBufReader
{
r
:
r
,
pos
:
0
,
buf
:
make
([]
byte
,
0
,
size
),
posLastIO
:
0
}
sb
:=
&
SeqBufReader
{
r
:
r
,
pos
:
0
,
buf
:
make
([]
byte
,
0
,
size
)
}
//
, posLastIO: 0}
return
sb
}
...
...
@@ -66,13 +72,25 @@ func NewSeqBufReaderSize(r io.ReaderAt, size int) *SeqBufReader {
// }
func
(
sb
*
SeqBufReader
)
ReadAt
(
p
[]
byte
,
pos
int64
)
(
int
,
error
)
{
// read-in last access positions and update them in *sb with current ones for next read
posLastAccess
:=
sb
.
posLastAccess
posLastFwdAfter
:=
sb
.
posLastFwdAfter
posLastBackward
:=
sb
.
posLastBackward
sb
.
posLastAccess
=
pos
if
pos
>=
posLastAccess
{
sb
.
posLastFwdAfter
=
pos
+
len64
(
p
)
}
else
{
sb
.
posLastBackward
=
pos
}
// if request size > buffer - read data directly
if
len
(
p
)
>
cap
(
sb
.
buf
)
{
// no copying from sb.buf here at all as if e.g. we could copy from sb.buf, the
// kernel can copy the same data from pagecache as well, and it will take the same time
// because for data in sb.buf corresponding page in pagecache has high p. to be hot.
//log.Printf("READ [%v, %v)\t#%v", pos, pos + len64(p), len(p))
sb
.
posLastIO
=
pos
//sb.posLastIO = pos
// TODO update lastAccess & lastFwd/lastBack
return
sb
.
r
.
ReadAt
(
p
,
pos
)
}
...
...
@@ -122,13 +140,42 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (int, error) {
// NOTE len(p) <= cap(sb.buf)
var
xpos
int64
// position for new IO request
if
pos
>=
sb
.
posLastIO
{
//if pos >= sb.posLastIO {
if
pos
>=
posLastAccess
{
// forward
xpos
=
pos
// if forward trend continues and buffering can be made adjacent to
// previous forward access - shift reading down right to after it.
xLastAfter
:=
posLastFwdAfter
+
int64
(
nhead
)
// XXX comment
if
xLastAfter
<=
xpos
&&
xpos
+
len64
(
p
)
<=
xLastAfter
+
cap64
(
sb
.
buf
)
{
xpos
=
xLastAfter
}
// XXX symmetry for "alternatively" in backward case
}
else
{
// backward
xpos
=
pos
// if backward trend continues and bufferring would overlap with
// previous backward access - shift reading up right to it.
if
xpos
<
posLastBackward
&&
posLastBackward
<
xpos
+
cap64
(
sb
.
buf
)
{
xpos
=
max64
(
posLastBackward
,
xpos
+
len64
(
p
))
-
cap64
(
sb
.
buf
)
// XXX recheck do we really need this ? ( was added for {122, 6, 121, 10} )
// XXX alternatively even if backward trend does not continue anymore
// but if this will overlap with last access (XXX load) range, probably
// it is better (we are optimizing for sequential access) to
// shift loading region down not to overlap.
}
else
if
xpos
+
cap64
(
sb
.
buf
)
>
posLastAccess
{
xpos
=
max64
(
posLastAccess
,
xpos
+
len64
(
p
))
-
cap64
(
sb
.
buf
)
}
// don't let reading go beyond start of the file
xpos
=
max64
(
xpos
,
0
)
/*
// by default we want to read forward, even when iterating backward:
// there are frequent jumps backward for reading a record there forward
xpos = pos
...
...
@@ -141,14 +188,15 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (int, error) {
// can overlap, if e.g. last access was big non-buffered read.
if xpos + cap64(sb.buf) > sb.posLastIO {
xpos = max64(sb.posLastIO, xpos + len64(p)) - cap64(sb.buf)
}
// don't let reading go beyond start of the file
xpos = max64(xpos, 0)
}
*/
}
//log.Printf("read [%v, %v)\t#%v", xpos, xpos + cap64(sb.buf), cap(sb.buf))
sb
.
posLastIO
=
xpos
//
sb.posLastIO = xpos
nn
,
err
:=
sb
.
r
.
ReadAt
(
sb
.
buf
[
:
cap
(
sb
.
buf
)],
xpos
)
// even if there was an error, or data partly read, we cannot retain
...
...
@@ -169,9 +217,9 @@ func (sb *SeqBufReader) ReadAt(p []byte, pos int64) (int, error) {
// - it was backward reading, and
// - original requst was narrower than buffer
// try to satisfy it once again directly
if
pos
!=
xpos
{
if
pos
!=
xpos
{
// FIXME pos != xpos no longer means backward
//log.Printf("read [%v, %v)\t#%v", pos, pos + len64(p), len(p))
sb
.
posLastIO
=
pos
//
sb.posLastIO = pos
nn
,
err
=
sb
.
r
.
ReadAt
(
p
,
pos
)
if
nn
<
len
(
p
)
{
return
nn
,
err
...
...
This diff is collapsed.
Click to expand it.
t/neo/storage/fs1/xbufio_test.go
View file @
03cfbf7e
...
...
@@ -9,6 +9,8 @@ import (
"errors"
"io"
"testing"
"fmt"
)
...
...
@@ -41,14 +43,15 @@ func (r *XReader) ReadAt(p []byte, pos int64) (n int, err error) {
// read @pos/len -> rb.pos, len(rb.buf)
var
xSeqBufTestv
=
[]
struct
{
pos
int64
;
Len
int
;
bufPos
int64
;
bufLen
int
}
{
// TODO add trend / not trend everywhere
{
40
,
5
,
40
,
10
},
// 1st access, forward by default
{
45
,
7
,
50
,
10
},
// part taken from buf, part read next, forward
{
45
,
7
,
50
,
10
},
// part taken from buf, part read next, forward
(trend)
{
52
,
5
,
50
,
10
},
// everything taken from buf
{
57
,
5
,
60
,
10
},
// part taken from buf, part read next
{
57
,
5
,
60
,
10
},
// part taken from buf, part read next
(trend)
{
60
,
11
,
60
,
10
},
// access > cap(buf), buf skipped
{
71
,
11
,
60
,
10
},
// access > cap(buf), once again
{
82
,
10
,
82
,
10
},
// access = cap(buf), should refill buf
{
92
,
5
,
92
,
8
},
// next access - should refill buffer, but only up to EIO range
{
92
,
5
,
92
,
8
},
// next access - should refill buffer
(trend)
, but only up to EIO range
{
97
,
4
,
100
,
0
},
// this triggers user-visible EIO, buffer scratched
{
101
,
5
,
101
,
0
},
// EIO again
{
105
,
5
,
105
,
10
},
// past EIO range - buffer refilled
...
...
@@ -57,7 +60,7 @@ var xSeqBufTestv = []struct {pos int64; Len int; bufPos int64; bufLen int} {
{
110
,
70
,
98
,
2
},
// very big access forward, buf untouched
{
180
,
70
,
98
,
2
},
// big access ~ forward
{
17
2
,
5
,
170
,
10
},
// backward: buffer refilled up to posLastIO
{
17
0
,
5
,
170
,
10
},
// backward: buffer refilled forward because prev backward reading was below
{
168
,
4
,
160
,
10
},
// backward: buffer refilled backward
{
162
,
6
,
160
,
10
},
// backward: all data read from buffer
{
150
,
12
,
160
,
10
},
// big backward: buf untouched
...
...
@@ -68,28 +71,48 @@ var xSeqBufTestv = []struct {pos int64; Len int; bufPos int64; bufLen int} {
{
122
,
6
,
121
,
10
},
// backward after forward: buf refilled backward
{
131
,
9
,
131
,
10
},
// forward again
{
136
,
20
,
131
,
10
},
// big forward starting from inside filled buf
{
128
,
4
,
126
,
10
},
// backward: buf refilled up to posLastIO
{
128
,
4
,
126
,
10
},
// backward (not trend): buf refilled up to posLastIO
// TODO interleaved forward + back-back-back
// TODO interleaved backward + fwd-fwd-fwd
{
5
,
4
,
5
,
10
},
// forward near file start
{
2
,
3
,
0
,
10
},
// backward: buf does not go beyong 0
{
40
,
0
,
0
,
10
},
// zero-sized out-of-buffer read do not change buffer
// backward vs EIO
{
110
,
1
,
110
,
10
},
// reset state: forward @110
{
105
,
7
,
100
,
0
},
// backward client after EIO: buf scratched but read request satisfied
{
110
,
1
,
110
,
10
},
// reset @110
{
103
,
5
,
100
,
0
},
// backward overlapping tail EIO: buf scratched, EIO -> user
{
110
,
1
,
110
,
10
},
// reset @110
{
101
,
2
,
100
,
0
},
// backward inside EIO range: buf scratched, EIO -> user
{
108
,
1
,
108
,
10
},
// reset @108
{
100
,
4
,
98
,
2
},
// backward = EIO range: buf filled < EIO range, EIO -> user
{
108
,
1
,
108
,
10
},
// reset @108
// backward (not trend) vs EIO
{
108
,
10
,
108
,
10
},
// reset @108
{
98
,
1
,
98
,
2
},
// backward not overlapping EIO: buf filled < EIO range
{
108
,
10
,
108
,
10
},
// reset @108
{
99
,
4
,
98
,
2
},
// backward overlapping head EIO: buf filled < EIO range, EIO -> user
{
108
,
10
,
108
,
10
},
// reset @108
{
99
,
6
,
98
,
2
},
// backward overlapping whole EIO range: buf filled <= EIO range, EIO -> user
{
108
,
1
,
108
,
10
},
// reset @108
{
108
,
10
,
108
,
10
},
// reset @108
{
100
,
4
,
98
,
2
},
// backward = EIO range: buf filled < EIO range, EIO -> user
{
110
,
10
,
110
,
10
},
// reset @110
{
101
,
2
,
100
,
0
},
// backward inside EIO range: buf scratched, EIO -> user
{
110
,
10
,
110
,
10
},
// reset @110
{
103
,
5
,
100
,
0
},
// backward overlapping tail EIO: buf scratched, EIO -> user
{
110
,
10
,
110
,
10
},
// reset state: forward @110
{
105
,
7
,
100
,
0
},
// backward client after EIO: buf scratched but read request satisfied
// backward (trend) vs EIO
// NOTE this is reverse of `backward (not trend) vs EIO
{
110
,
10
,
110
,
10
},
// reset state: forward @110
{
105
,
7
,
100
,
0
},
// backward client after EIO: buf scratched but read request satisfied
{
110
,
10
,
110
,
10
},
// reset @110
{
103
,
5
,
98
,
2
},
// backward overlapping tail EIO: buf scratched (XXX), EIO -> user
{
110
,
10
,
110
,
10
},
// reset @110
{
101
,
2
,
93
,
7
},
// backward inside EIO range: buf scratched (XXX), EIO -> user
{
108
,
10
,
108
,
10
},
// reset @108
{
100
,
4
,
94
,
6
},
// backward = EIO range: buf filled < EIO range, EIO -> user
{
108
,
10
,
108
,
10
},
// reset @108
{
99
,
6
,
95
,
5
},
// backward overlapping whole EIO range: buf filled <= EIO range, EIO -> user
{
108
,
10
,
108
,
10
},
// reset @108
{
99
,
4
,
98
,
2
},
// backward overlapping head EIO: buf filled < EIO range, EIO -> user
{
108
,
1
,
108
,
10
},
// reset @108
{
98
,
1
,
98
,
2
},
// nackward not overlapping EIO: buf filled < EIO range
{
108
,
10
,
108
,
10
},
// reset @108
{
98
,
1
,
89
,
10
},
// backward not overlapping EIO: buf filled according to backward trend
{
250
,
4
,
250
,
6
},
// access near EOF - buffer fill hits EOF, but not returns it to client
{
254
,
5
,
256
,
0
},
// access overlapping EOF - EOF returned, buf scratched
...
...
@@ -103,6 +126,7 @@ func TestSeqBufReader(t *testing.T) {
rb
:=
NewSeqBufReaderSize
(
r
,
10
)
// with 10 it is easier to do/check math for a human
for
_
,
tt
:=
range
xSeqBufTestv
{
fmt
.
Println
(
tt
)
pOk
:=
make
([]
byte
,
tt
.
Len
)
pB
:=
make
([]
byte
,
tt
.
Len
)
...
...
This diff is collapsed.
Click to expand it.
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