Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Kirill Smelkov
wendelin.core
Commits
7811163e
Commit
7811163e
authored
Feb 04, 2019
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
a20f81e1
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
105 additions
and
38 deletions
+105
-38
wcfs/wcfs.go
wcfs/wcfs.go
+3
-2
wcfs/zδtail_i64.go
wcfs/zδtail_i64.go
+102
-36
No files found.
wcfs/wcfs.go
View file @
7811163e
...
...
@@ -413,11 +413,12 @@ type Root struct {
zstor
zodb
.
IStorage
// ZODB DB handle for zstor.
// keeps cache of connections for @<rev>/ accesse
s
.
// only one connection is used for
for
each @<rev>.
// keeps cache of connections for @<rev>/ accesse.
// only one connection is used for each @<rev>.
zdb
*
zodb
.
DB
// directory + ZODB connection for head/
// (zhead is Resync'ed and is kept outside zdb pool)
head
*
Head
// directories + ZODB connections for @<rev>/
...
...
wcfs/zδtail_i64.go
View file @
7811163e
// Code generated by gen-δtail I64 int64; DO NOT EDIT.
// (from lab.nexedi.com/kirr/neo/go/zodb @ v1.9-2
080-gd1f63f32
)
// (from lab.nexedi.com/kirr/neo/go/zodb @ v1.9-2
136-g1742e47b
)
// Copyright (C) 2018-2019 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
...
...
@@ -35,7 +35,7 @@ import (
//
// It semantically consists of
//
// [](rev↑, []id)
XXX + head?
// [](rev↑, []id)
; rev ∈ (tail, head]
//
// and index
//
...
...
@@ -43,15 +43,17 @@ import (
//
// where
//
// rev - is ZODB revision, and
// id - is an identifier of what has been changed(*)
// rev - is ZODB revision,
// id - is an identifier of what has been changed(*), and
// (tail, head] - is covered revision range
//
// It provides operations to
//
// - append information to the tail about next revision,
// - forget information in the tail past specified revision, and
// - query the tail about what is last revision that changed an id.
// - query the tail about what head/tail XXX?
// - forget information in the tail past specified revision,
// - query the tail for slice with rev ∈ (lo, hi],
// - query the tail about what is last revision that changed an id,
// - query the tail for len and (tail, head].
//
// ΔTailI64 is safe to access for multiple-readers / single writer.
//
...
...
@@ -61,32 +63,89 @@ import (
// #blk - file block number, when ΔTailI64 represents changes to a file.
type
ΔTailI64
struct
{
head
zodb
.
Tid
tailv
[]
δRevEntryI64
tail
zodb
.
Tid
tailv
[]
ΔRevEntry
// XXX -> revv ?
lastRevOf
map
[
int64
]
zodb
.
Tid
// index for LastRevOf queries
// TODO also add either tailv idx <-> rev index, or lastRevOf -> tailv idx
// (if linear back-scan of δRevEntryI64 starts to eat cpu).
// XXX -> lastRevOf = {} oid -> []rev↑ if linear scan in LastRevOf starts to eat cpu
}
// δRevEntryI64 represents information of what have been changed in one revision.
type
δRevEntryI64
struct
{
rev
zodb
.
Tid
changev
[]
int64
// ΔRevEntry represents information of what have been changed in one revision.
//
// XXX -> ΔRevEntry?
type
ΔRevEntry
struct
{
Rev
zodb
.
Tid
Changev
[]
int64
}
// NewΔTailI64 creates new ΔTailI64 object.
func
NewΔTailI64
()
*
ΔTailI64
{
return
&
ΔTailI64
{
lastRevOf
:
make
(
map
[
int64
]
zodb
.
Tid
)}
//
// Initial coverage of created ΔTailI64 is (at₀, at₀].
func
NewΔTailI64
(
at0
zodb
.
Tid
)
*
ΔTailI64
{
return
&
ΔTailI64
{
head
:
at0
,
tail
:
at0
,
lastRevOf
:
make
(
map
[
int64
]
zodb
.
Tid
),
}
}
// Head returns database state starting from which δtail has history coverage. XXX
// Len returns number of revisions.
func
(
δtail
*
ΔTailI64
)
Len
()
int
{
return
len
(
δtail
.
tailv
)
}
// Head returns newest database state for which δtail has history coverage.
//
// For newly created ΔTailI64 Head returns 0.
// Head is ↑, in particular it does not go back to 0 when δtail becomes empty.
// Head is ↑ on Append, in particular it does not ↓ on Forget even if δtail becomes empty.
func
(
δtail
*
ΔTailI64
)
Head
()
zodb
.
Tid
{
return
δtail
.
head
}
// Tail returns oldest database state for which δtail has history coverage.
//
// Tail is ↑= on Forget, even if δtail becomes empty.
func
(
δtail
*
ΔTailI64
)
Tail
()
zodb
.
Tid
{
return
δtail
.
tail
}
// SliceByRev returns δtail slice of elements with .rev ∈ (low, high].
//
// it must be called with the following condition:
//
// tail ≤ low ≤ high ≤ head
//
// the caller must not modify returned slice.
//
// Note: contrary to regular go slicing, low is exclusive while high is inclusive.
func
(
δtail
*
ΔTailI64
)
SliceByRev
(
low
,
high
zodb
.
Tid
)
/*readonly*/
[]
ΔRevEntry
{
tail
:=
δtail
.
Tail
()
head
:=
δtail
.
head
if
!
(
tail
<=
low
&&
low
<=
high
&&
high
<=
head
)
{
panic
(
fmt
.
Sprintf
(
"δtail.Slice: invalid query: (%s, %s]; (tail, head] = (%s, %s]"
,
low
,
high
,
tail
,
head
))
}
tailv
:=
δtail
.
tailv
// ex (0,0] tail..head = 0..0
if
len
(
tailv
)
==
0
{
return
tailv
}
// find max j : [j].rev ≤ high XXX linear scan -> binary search
j
:=
len
(
tailv
)
-
1
for
;
j
>=
0
&&
tailv
[
j
]
.
Rev
>
high
;
j
--
{}
if
j
<
0
{
return
nil
// ø
}
// find max i : [i].rev > low XXX linear scan -> binary search
i
:=
j
for
;
i
>=
0
&&
tailv
[
i
]
.
Rev
>
low
;
i
--
{}
i
++
return
tailv
[
i
:
j
+
1
]
}
// XXX add way to extend coverage without appending changed data? (i.e. if a
// txn did not change file at all) -> but then it is simply .Append(rev, nil)?
...
...
@@ -100,24 +159,29 @@ func (δtail *ΔTailI64) Append(rev zodb.Tid, changev []int64) {
}
δtail
.
head
=
rev
δtail
.
tailv
=
append
(
δtail
.
tailv
,
δRevEntryI64
{
rev
,
changev
})
δtail
.
tailv
=
append
(
δtail
.
tailv
,
ΔRevEntry
{
rev
,
changev
})
for
_
,
id
:=
range
changev
{
δtail
.
lastRevOf
[
id
]
=
rev
}
}
// ForgetBefore discards all δtail entries with rev < revCut.
func
(
δtail
*
ΔTailI64
)
ForgetBefore
(
revCut
zodb
.
Tid
)
{
// ForgetPast discards all δtail entries with rev ≤ revCut.
func
(
δtail
*
ΔTailI64
)
ForgetPast
(
revCut
zodb
.
Tid
)
{
// revCut ≤ tail: nothing to do; don't let .tail go ↓
if
revCut
<=
δtail
.
tail
{
return
}
icut
:=
0
for
i
,
δ
:=
range
δtail
.
tailv
{
rev
:=
δ
.
r
ev
if
rev
>
=
revCut
{
rev
:=
δ
.
R
ev
if
rev
>
revCut
{
break
}
icut
=
i
+
1
// if forgotten revision was last for id, we have to update lastRevOf index
for
_
,
id
:=
range
δ
.
c
hangev
{
for
_
,
id
:=
range
δ
.
C
hangev
{
if
δtail
.
lastRevOf
[
id
]
==
rev
{
delete
(
δtail
.
lastRevOf
,
id
)
}
...
...
@@ -128,9 +192,11 @@ func (δtail *ΔTailI64) ForgetBefore(revCut zodb.Tid) {
// 1) growing underlying storage array indefinitely
// 2) keeping underlying storage after forget
l
:=
len
(
δtail
.
tailv
)
-
icut
tailv
:=
make
([]
δRevEntryI64
,
l
)
tailv
:=
make
([]
ΔRevEntry
,
l
)
copy
(
tailv
,
δtail
.
tailv
[
icut
:
])
δtail
.
tailv
=
tailv
δtail
.
tail
=
revCut
}
// LastRevOf tries to return what was the last revision that changed id as of at database state.
...
...
@@ -144,14 +210,14 @@ func (δtail *ΔTailI64) ForgetBefore(revCut zodb.Tid) {
// LastRevOf(id, at) = at
//
// 2) if δtail has an entry corresponding to id change, it gives exactly the
//
last revision that changed id:
// last revision that changed id:
//
// # at ∈ [min(rev ∈ δtail), max(rev ∈ δtail)]
// # ∃ rev ∈ δtail: rev changed id && rev ≤ at
// LastRevOf(id, at) = max(rev: rev changed id && rev ≤ at)
//
// 3) if δtail does not contain appropriate record with id - it returns δtail's
//
lower bound as the estimate for the upper bound of the last id revision:
// lower bound as the estimate for the upper bound of the last id revision:
//
// # at ∈ [min(rev ∈ δtail), max(rev ∈ δtail)]
// # ∄ rev ∈ δtail: rev changed id && rev ≤ at
...
...
@@ -165,8 +231,8 @@ func (δtail *ΔTailI64) LastRevOf(id int64, at zodb.Tid) (_ zodb.Tid, exact boo
if
l
==
0
{
return
at
,
false
}
revMin
:=
δtail
.
tailv
[
0
]
.
r
ev
revMax
:=
δtail
.
tailv
[
l
-
1
]
.
r
ev
revMin
:=
δtail
.
tailv
[
0
]
.
R
ev
revMax
:=
δtail
.
tailv
[
l
-
1
]
.
R
ev
if
!
(
revMin
<=
at
&&
at
<=
revMax
)
{
return
at
,
false
}
...
...
@@ -174,7 +240,7 @@ func (δtail *ΔTailI64) LastRevOf(id int64, at zodb.Tid) (_ zodb.Tid, exact boo
// we have the coverage
rev
,
ok
:=
δtail
.
lastRevOf
[
id
]
if
!
ok
{
return
δtail
.
tailv
[
0
]
.
r
ev
,
false
return
δtail
.
tailv
[
0
]
.
R
ev
,
false
}
if
rev
<=
at
{
...
...
@@ -182,20 +248,20 @@ func (δtail *ΔTailI64) LastRevOf(id int64, at zodb.Tid) (_ zodb.Tid, exact boo
}
// what's in index is after at - scan tailv back to find appropriate entry
// XXX linear scan
// XXX linear scan
- see .lastRevOf comment.
for
i
:=
l
-
1
;
i
>=
0
;
i
--
{
δ
:=
δtail
.
tailv
[
i
]
if
δ
.
r
ev
>
at
{
if
δ
.
R
ev
>
at
{
continue
}
for
_
,
δid
:=
range
δ
.
c
hangev
{
for
_
,
δid
:=
range
δ
.
C
hangev
{
if
id
==
δid
{
return
δ
.
r
ev
,
true
return
δ
.
R
ev
,
true
}
}
}
// nothing found
return
δtail
.
tailv
[
0
]
.
r
ev
,
false
return
δtail
.
tailv
[
0
]
.
R
ev
,
false
}
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