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
4672ebb0
Commit
4672ebb0
authored
Dec 20, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X Access to Connection.cache
parent
f7789b0e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
59 additions
and
32 deletions
+59
-32
go/zodb/connection.go
go/zodb/connection.go
+57
-31
go/zodb/db.go
go/zodb/db.go
+1
-0
go/zodb/persistent.go
go/zodb/persistent.go
+1
-1
No files found.
go/zodb/connection.go
View file @
4672ebb0
...
@@ -50,10 +50,24 @@ type Connection struct {
...
@@ -50,10 +50,24 @@ type Connection struct {
txn
transaction
.
Transaction
// opened under this txn; nil if idle in DB pool.
txn
transaction
.
Transaction
// opened under this txn; nil if idle in DB pool.
at
Tid
// current view of database; stable inside a transaction.
at
Tid
// current view of database; stable inside a transaction.
// XXX document it is only a cache - i.e. this is only partial mapping, not for whole db
cache
LiveCache
// cache of connection's in-RAM objects
// {} oid -> obj
}
//
// rationale:
// LiveCache keeps registry of live in-RAM objects for a Connection.
//
// It semantically consists of
//
// {} oid -> obj
//
// but does not hold strong reference to cached objects.
//
// LiveCache is safe for multiple simultaneous read access.
// LiveCache is not safe for multiple simultaneous read/write access -
// the caller must explicitly serialize access with e.g. .Lock() .
//
// XXX try to hide locking from user?
type
LiveCache
struct
{
// rationale for using weakref:
//
//
// on invalidations: we need to go oid -> obj and invalidate it.
// on invalidations: we need to go oid -> obj and invalidate it.
// -> Connection need to keep {} oid -> obj.
// -> Connection need to keep {} oid -> obj.
...
@@ -99,7 +113,8 @@ type Connection struct {
...
@@ -99,7 +113,8 @@ type Connection struct {
//
//
// NOTE2 finalizers don't run on when they are attached to an object in cycle.
// NOTE2 finalizers don't run on when they are attached to an object in cycle.
// Hopefully we don't have cycles with BTree/Bucket.
// Hopefully we don't have cycles with BTree/Bucket.
objmu
sync
.
Mutex
sync
.
Mutex
objtab
map
[
Oid
]
*
weak
.
Ref
// oid -> weak.Ref(IPersistent)
objtab
map
[
Oid
]
*
weak
.
Ref
// oid -> weak.Ref(IPersistent)
// hooks for application to influence live caching decisions.
// hooks for application to influence live caching decisions.
...
@@ -124,10 +139,12 @@ type LiveCacheControl interface {
...
@@ -124,10 +139,12 @@ type LiveCacheControl interface {
// newConnection creates new Connection associated with db.
// newConnection creates new Connection associated with db.
func
newConnection
(
db
*
DB
,
at
Tid
)
*
Connection
{
func
newConnection
(
db
*
DB
,
at
Tid
)
*
Connection
{
return
&
Connection
{
return
&
Connection
{
stor
:
db
.
stor
,
stor
:
db
.
stor
,
db
:
db
,
db
:
db
,
at
:
at
,
at
:
at
,
objtab
:
make
(
map
[
Oid
]
*
weak
.
Ref
),
cache
:
LiveCache
{
objtab
:
make
(
map
[
Oid
]
*
weak
.
Ref
),
},
}
}
}
}
...
@@ -137,6 +154,11 @@ func (conn *Connection) At() Tid {
...
@@ -137,6 +154,11 @@ func (conn *Connection) At() Tid {
return
conn
.
at
return
conn
.
at
}
}
// Cache returns connection's cache of live objects.
func
(
conn
*
Connection
)
Cache
()
*
LiveCache
{
return
&
conn
.
cache
}
// wrongClassError is the error cause returned when ZODB object's class is not what was expected.
// wrongClassError is the error cause returned when ZODB object's class is not what was expected.
type
wrongClassError
struct
{
type
wrongClassError
struct
{
want
,
have
string
want
,
have
string
...
@@ -146,31 +168,39 @@ func (e *wrongClassError) Error() string {
...
@@ -146,31 +168,39 @@ func (e *wrongClassError) Error() string {
return
fmt
.
Sprintf
(
"wrong class: want %q; have %q"
,
e
.
want
,
e
.
have
)
return
fmt
.
Sprintf
(
"wrong class: want %q; have %q"
,
e
.
want
,
e
.
have
)
}
}
//
get is like Get, but used when we already know object class
.
//
Get lookups object corresponding to oid in the cache
.
//
//
// Use-case: in ZODB references are (pyclass, oid), so new ghost is created
// It is not safe to call Get from multiple goroutines simultaneously.
// without further loading anything.
func
(
cache
*
LiveCache
)
Get
(
oid
Oid
)
IPersistent
{
func
(
conn
*
Connection
)
get
(
class
string
,
oid
Oid
)
(
IPersistent
,
error
)
{
wobj
:=
cache
.
objtab
[
oid
]
conn
.
objmu
.
Lock
()
// XXX -> rlock?
wobj
:=
conn
.
objtab
[
oid
]
var
obj
IPersistent
var
obj
IPersistent
checkClass
:=
false
if
wobj
!=
nil
{
if
wobj
!=
nil
{
if
xobj
:=
wobj
.
Get
();
xobj
!=
nil
{
if
xobj
:=
wobj
.
Get
();
xobj
!=
nil
{
obj
=
xobj
.
(
IPersistent
)
obj
=
xobj
.
(
IPersistent
)
}
}
}
}
return
obj
}
// get is like Get, but used when we already know object class.
//
// Use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything.
func
(
conn
*
Connection
)
get
(
class
string
,
oid
Oid
)
(
IPersistent
,
error
)
{
conn
.
cache
.
Lock
()
// XXX -> rlock?
obj
:=
conn
.
cache
.
Get
(
oid
)
checkClass
:=
false
if
obj
==
nil
{
if
obj
==
nil
{
obj
=
newGhost
(
class
,
oid
,
conn
)
obj
=
newGhost
(
class
,
oid
,
conn
)
//if obj == nil {
//if obj == nil {
// conn.
objmu
.Unlock()
// conn.
cache
.Unlock()
// return nil, fmt.Errorf("get %s: class %q not supported", Xid{conn.at, oid}, class)
// return nil, fmt.Errorf("get %s: class %q not supported", Xid{conn.at, oid}, class)
//}
//}
conn
.
objtab
[
oid
]
=
weak
.
NewRef
(
obj
)
conn
.
cache
.
objtab
[
oid
]
=
weak
.
NewRef
(
obj
)
}
else
{
}
else
{
checkClass
=
true
checkClass
=
true
}
}
conn
.
objmu
.
Unlock
()
conn
.
cache
.
Unlock
()
if
checkClass
{
if
checkClass
{
if
cls
:=
ClassOf
(
obj
);
class
!=
cls
{
if
cls
:=
ClassOf
(
obj
);
class
!=
cls
{
...
@@ -196,20 +226,16 @@ func (conn *Connection) Get(ctx context.Context, oid Oid) (_ IPersistent, err er
...
@@ -196,20 +226,16 @@ func (conn *Connection) Get(ctx context.Context, oid Oid) (_ IPersistent, err er
conn
.
checkTxnCtx
(
ctx
,
"Get"
)
conn
.
checkTxnCtx
(
ctx
,
"Get"
)
defer
xerr
.
Contextf
(
&
err
,
"Get %s"
,
oid
)
defer
xerr
.
Contextf
(
&
err
,
"Get %s"
,
oid
)
conn
.
objmu
.
Lock
()
// XXX -> rlock?
conn
.
cache
.
Lock
()
// XXX -> rlock?
wobj
:=
conn
.
objtab
[
oid
]
obj
:=
conn
.
cache
.
Get
(
oid
)
var
xobj
interface
{}
conn
.
cache
.
Unlock
()
if
wobj
!=
nil
{
xobj
=
wobj
.
Get
()
}
conn
.
objmu
.
Unlock
()
// object was already there in
objtab
.
// object was already there in
cache
.
if
x
obj
!=
nil
{
if
obj
!=
nil
{
return
xobj
.
(
IPersistent
)
,
nil
return
obj
,
nil
}
}
// object is not
there in objtab
- raw load it, get its class -> get(pyclass, oid)
// object is not
in cache
- raw load it, get its class -> get(pyclass, oid)
// XXX "py always" hardcoded
// XXX "py always" hardcoded
class
,
pystate
,
serial
,
err
:=
conn
.
loadpy
(
ctx
,
oid
)
class
,
pystate
,
serial
,
err
:=
conn
.
loadpy
(
ctx
,
oid
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -217,7 +243,7 @@ func (conn *Connection) Get(ctx context.Context, oid Oid) (_ IPersistent, err er
...
@@ -217,7 +243,7 @@ func (conn *Connection) Get(ctx context.Context, oid Oid) (_ IPersistent, err er
return
nil
,
err
return
nil
,
err
}
}
obj
,
err
:
=
conn
.
get
(
class
,
oid
)
obj
,
err
=
conn
.
get
(
class
,
oid
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
go/zodb/db.go
View file @
4672ebb0
...
@@ -52,6 +52,7 @@ type DB struct {
...
@@ -52,6 +52,7 @@ type DB struct {
// information about invalidations
// information about invalidations
// XXX -> Storage. XXX or -> Cache? (so it is not duplicated many times for many DB case)
// XXX -> Storage. XXX or -> Cache? (so it is not duplicated many times for many DB case)
// XXX -> ΔTail<tid, oid>
invTab
[]
invEntry
// order by ↑= .tid
invTab
[]
invEntry
// order by ↑= .tid
}
}
...
...
go/zodb/persistent.go
View file @
4672ebb0
...
@@ -224,7 +224,7 @@ func (obj *Persistent) PDeactivate() {
...
@@ -224,7 +224,7 @@ func (obj *Persistent) PDeactivate() {
// no constant load/unload on object access. XXX -> MRU cache?
// no constant load/unload on object access. XXX -> MRU cache?
// NOTE wcfs manages its objects explicitly and does not need this.
// NOTE wcfs manages its objects explicitly and does not need this.
if
cc
:=
obj
.
jar
.
cacheControl
;
cc
!=
nil
{
if
cc
:=
obj
.
jar
.
cache
.
cache
Control
;
cc
!=
nil
{
if
!
cc
.
WantEvict
(
obj
.
instance
)
{
if
!
cc
.
WantEvict
(
obj
.
instance
)
{
return
return
}
}
...
...
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