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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Joshua
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