Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
c4a0aa66
Commit
c4a0aa66
authored
Jan 24, 2019
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
b03da68b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
131 additions
and
34 deletions
+131
-34
go/zodb/db.go
go/zodb/db.go
+82
-21
go/zodb/δtail.go
go/zodb/δtail.go
+37
-11
go/zodb/δtail.go.cat-generic
go/zodb/δtail.go.cat-generic
+12
-2
No files found.
go/zodb/db.go
View file @
c4a0aa66
...
@@ -48,16 +48,26 @@ type DB struct {
...
@@ -48,16 +48,26 @@ type DB struct {
stor
IStorage
stor
IStorage
mu
sync
.
Mutex
mu
sync
.
Mutex
// connections nearby current db
// XXX covered by δtail
// live cache is reused through finding conn with nearby at and
// invalidating live objects based on δtail info.
connv
[]
*
Connection
// order by ↑= .at
connv
[]
*
Connection
// order by ↑= .at
// XXX -> Storage. XXX or -> Cache? (so it is not duplicated many times for many DB case)
// // connections that are too far away from current db
// // not covered by δtail
// historicv []*Connections // XXX needed? (think again)
// δtail of database changes for invalidations
// δtail of database changes for invalidations
// min(rev) = min(conn.at) for all conn ∈ db (opened and in the pool)
// min(rev) = min(conn.at) for all conn ∈ db (opened and in the pool)
// XXX + min(conn.at) for all conn ∈ waiting/opening.
δtail
*
ΔTail
// [](rev↑, []oid)
δtail
*
ΔTail
// [](rev↑, []oid)
// openers waiting for δtail.Head to become covering their at.
// openers waiting for δtail.Head to become covering their at.
δwait
map
[
δwaiter
]
struct
{}
// set{(at, ready)} XXX -> set_δwaiter?
δwait
map
[
δwaiter
]
struct
{}
// set{(at, ready)} XXX -> set_δwaiter?
// XXX δtail/δwait -> Storage. XXX or -> Cache? (so it is not duplicated many times for many DB case)
}
}
// δwaiter represents someone waiting for δtail.Head to become ≥ at.
// δwaiter represents someone waiting for δtail.Head to become ≥ at.
...
@@ -175,12 +185,13 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
...
@@ -175,12 +185,13 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
head
:=
Tid
(
0
)
head
:=
Tid
(
0
)
if
opt
.
NoSync
{
if
opt
.
NoSync
{
// XXX locking
db
.
mu
.
Lock
()
// XXX prevent retrieved head to be removed from δtail
// XXX prevent retrieved head to be removed from δtail ?
head
=
db
.
δtail
.
Head
()
// = 0 if empty
head
=
db
.
δtail
.
Head
()
// = 0 if δtail was not yet initialized with first event
db
.
mu
.
Unlock
()
}
}
// !NoSync or δtail
empty
// !NoSync or δtail
!initialized
// sync storage for lastTid
// sync storage for lastTid
if
head
==
0
{
if
head
==
0
{
var
err
error
var
err
error
...
@@ -197,24 +208,71 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
...
@@ -197,24 +208,71 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
at
=
head
at
=
head
}
}
// wait till .δtail.head is up to date covering ≥ at
var
δready
chan
struct
{}
db
.
mu
.
Lock
()
db
.
mu
.
Lock
()
δhead
:=
db
.
δtail
.
Head
()
// XXX prevent head from going away?
if
δhead
<
at
{
δready
=
make
(
chan
struct
{})
db
.
δwait
[
δwaiter
{
at
,
δready
}]
=
struct
{}{}
}
db
.
mu
.
Unlock
()
if
δready
!=
nil
{
// check if we already have the exact match
select
{
conn
=
db
.
get
(
at
,
at
)
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
if
conn
==
nil
{
switch
{
// too far in the past -> historic connection
case
at
<
db
.
δtail
.
Tail
()
:
//conn = db.get(at, at)
conn
=
newConnection
(
db
,
at
)
// δtail !initialized yet
case
db
.
δtail
.
Head
()
==
0
:
// XXX δtail could be not yet initialized, but e.g. last_tid changed
// -> we have to wait for δtail not to loose just-released live cache
conn
=
newConnection
(
db
,
at
)
// we already have some history coverage
default
:
if
at
>
δhead
{
// XXX wait
// XXX -> retry loop (δtail.tail might go over at)
}
// at ∈ [δtail, δhead]
conn
=
get
(
δtail
.
Tail
(),
at
)
if
conn
==
nil
{
conn
=
newConnection
(
db
,
at
)
}
else
{
// invalidate changed live objects
for
_
,
δ
:=
range
δtail
.
Slice
(
conn
.
at
,
at
)
{
for
_
,
oid
:=
range
δ
.
changev
{
obj
:=
conn
.
cache
.
Get
(
oid
)
if
obj
!=
nil
{
obj
.
PInvalidate
()
}
}
}
conn
.
at
=
at
}
}
db
.
mu
.
Unlock
()
// wait till .δtail.head is up to date covering ≥ at
var
δready
chan
struct
{}
db
.
mu
.
Lock
()
δhead
:=
db
.
δtail
.
Head
()
// XXX prevent head from going away?
if
δhead
<
at
{
δready
=
make
(
chan
struct
{})
db
.
δwait
[
δwaiter
{
at
,
δready
}]
=
struct
{}{}
}
db
.
mu
.
Unlock
()
if
δready
!=
nil
{
select
{
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
case
<-
δready
:
case
<-
δready
:
// ok
// ok
}
}
}
}
}
...
@@ -229,11 +287,14 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
...
@@ -229,11 +287,14 @@ func (db *DB) Open(ctx context.Context, opt *ConnOptions) (_ *Connection, err er
// get returns connection from db pool most close to at.
// get returns connection from db pool most close to at.
//
//
// it creates new one if there is no close-enough connection in the pool.
// it creates new one if there is no close-enough connection in the pool. XXX -> no
// XXX -> must be run with db.mu locked.
func
(
db
*
DB
)
get
(
at
Tid
)
*
Connection
{
func
(
db
*
DB
)
get
(
at
Tid
)
*
Connection
{
db
.
mu
.
Lock
()
db
.
mu
.
Lock
()
defer
db
.
mu
.
Unlock
()
defer
db
.
mu
.
Unlock
()
// XXX at < δtail.Tail -> getHistoric; else -> here
l
:=
len
(
db
.
connv
)
l
:=
len
(
db
.
connv
)
// find connv index corresponding to at:
// find connv index corresponding to at:
...
...
go/zodb/δtail.go
View file @
c4a0aa66
...
@@ -56,17 +56,11 @@ import (
...
@@ -56,17 +56,11 @@ import (
// #blk - file block number, when ΔTail represents changes to a file.
// #blk - file block number, when ΔTail represents changes to a file.
type
ΔTail
struct
{
type
ΔTail
struct
{
head
Tid
head
Tid
tailv
[]
δRevEntry
tailv
[]
CommitEvent
lastRevOf
map
[
Oid
]
Tid
// index for LastRevOf queries
lastRevOf
map
[
Oid
]
Tid
// index for LastRevOf queries
// TODO also add either tailv idx <-> rev index, or lastRevOf -> tailv idx
// TODO also add either tailv idx <-> rev index, or lastRevOf -> tailv idx
// (if linear back-scan of δRevEntry starts to eat cpu).
// (if linear back-scan of CommitEvent starts to eat cpu).
}
// δRevEntry represents information of what have been changed in one revision.
type
δRevEntry
struct
{
rev
Tid
changev
[]
Oid
}
}
// NewΔTail creates new ΔTail object.
// NewΔTail creates new ΔTail object.
...
@@ -82,7 +76,39 @@ func (δtail *ΔTail) Head() Tid {
...
@@ -82,7 +76,39 @@ func (δtail *ΔTail) Head() Tid {
return
δtail
.
head
return
δtail
.
head
}
}
// XXX + Tail?
// XXX doc XXX tests XXX Tail -> End? Back?
func
(
δtail
*
ΔTail
)
Tail
()
Tid
{
if
len
(
δtail
.
tailv
)
>
0
{
return
δtail
.
tailv
[
0
]
.
rev
}
return
δtail
.
head
}
// XXX -> git tailv subslice in (low, high]
// XXX tail <= low <= high <= head, else panic
func
(
δtail
*
ΔTail
)
Slice
(
low
,
high
Tid
)
[]
CommitEvent
{
tail
:=
δtail
.
Tail
()
head
:=
δtail
.
head
if
!
(
tail
<=
low
&&
low
<=
high
&&
high
<=
head
)
{
panic
(
fmt
.
Sprintf
(
"δtail.Slice: (%s, %s] invalid; tail..head = %s..%s"
,
low
,
high
,
tail
,
head
))
}
// ex (0,0] tail..head = 0..0
if
len
(
tailv
)
==
0
{
return
tailv
}
// find max j : [j].rev <= high
j
:=
len
(
tailv
)
-
1
for
;
tailv
[
j
]
.
rev
>
high
;
j
--
{}
// find max i : [i].rev > low
i
:=
j
for
;
i
>=
0
&&
tailv
[
i
]
.
rev
>
low
;
i
--
{}
i
++
return
tailv
[
i
:
j
]
}
// XXX add way to extend coverage without appending changed data? (i.e. if a
// 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)?
// txn did not change file at all) -> but then it is simply .Append(rev, nil)?
...
@@ -97,7 +123,7 @@ func (δtail *ΔTail) Append(rev Tid, changev []Oid) {
...
@@ -97,7 +123,7 @@ func (δtail *ΔTail) Append(rev Tid, changev []Oid) {
}
}
δtail
.
head
=
rev
δtail
.
head
=
rev
δtail
.
tailv
=
append
(
δtail
.
tailv
,
δRevEntry
{
rev
,
changev
})
δtail
.
tailv
=
append
(
δtail
.
tailv
,
CommitEvent
{
rev
,
changev
})
for
_
,
id
:=
range
changev
{
for
_
,
id
:=
range
changev
{
δtail
.
lastRevOf
[
id
]
=
rev
δtail
.
lastRevOf
[
id
]
=
rev
}
}
...
@@ -125,7 +151,7 @@ func (δtail *ΔTail) ForgetBefore(revCut Tid) {
...
@@ -125,7 +151,7 @@ func (δtail *ΔTail) ForgetBefore(revCut Tid) {
// 1) growing underlying storage array indefinitely
// 1) growing underlying storage array indefinitely
// 2) keeping underlying storage after forget
// 2) keeping underlying storage after forget
l
:=
len
(
δtail
.
tailv
)
-
icut
l
:=
len
(
δtail
.
tailv
)
-
icut
tailv
:=
make
([]
δRevEntry
,
l
)
tailv
:=
make
([]
CommitEvent
,
l
)
copy
(
tailv
,
δtail
.
tailv
[
icut
:
])
copy
(
tailv
,
δtail
.
tailv
[
icut
:
])
δtail
.
tailv
=
tailv
δtail
.
tailv
=
tailv
}
}
...
...
go/zodb/δtail.go.cat-generic
View file @
c4a0aa66
...
@@ -29,7 +29,7 @@
...
@@ -29,7 +29,7 @@
# The types that are emitted are
# The types that are emitted are
#
#
# ΔTail
# ΔTail
#
δ
RevEntry
#
Δ
RevEntry
input
=
$(
dirname
$0
)
/δtail.go
input
=
$(
dirname
$0
)
/δtail.go
...
@@ -37,4 +37,14 @@ cat "$input" |sed \
...
@@ -37,4 +37,14 @@ cat "$input" |sed \
-e
's/package zodb/package PACKAGE/g'
\
-e
's/package zodb/package PACKAGE/g'
\
-e
'/package PACKAGE/a \\nimport "lab.nexedi.com/kirr/neo/go/zodb"'
\
-e
'/package PACKAGE/a \\nimport "lab.nexedi.com/kirr/neo/go/zodb"'
\
-e
's/Tid/zodb.Tid/g'
\
-e
's/Tid/zodb.Tid/g'
\
-e
's/Oid/ID/g'
-e
's/Oid/ID/g'
\
-e
's/CommitEvent/ΔRevEntry/g'
cat
<<
EOF
// ΔRevEntry represents information of what have been changed in one revision.
type ΔRevEntry struct {
Rev Tid
Changev []ID
}
EOF
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