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
c31c4855
Commit
c31c4855
authored
Jul 20, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
2f8b5e03
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
48 additions
and
50 deletions
+48
-50
go/zodb/btree/btree.go
go/zodb/btree/btree.go
+7
-7
go/zodb/internal/weak/weak.go
go/zodb/internal/weak/weak.go
+10
-12
go/zodb/internal/weak/weak_test.go
go/zodb/internal/weak/weak_test.go
+2
-2
go/zodb/persistent.go
go/zodb/persistent.go
+14
-14
go/zodb/zodbpy.go
go/zodb/zodbpy.go
+15
-15
No files found.
go/zodb/btree/btree.go
View file @
c31c4855
...
@@ -19,7 +19,7 @@ import (
...
@@ -19,7 +19,7 @@ import (
"sort"
"sort"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xerr"
//
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
pickle
"github.com/kisielk/og-rek"
pickle
"github.com/kisielk/og-rek"
)
)
...
@@ -37,7 +37,7 @@ type KEY int64
...
@@ -37,7 +37,7 @@ type KEY int64
// are chained together via 'next', so that the entire BTree contents
// are chained together via 'next', so that the entire BTree contents
// can be traversed in sorted order quickly and easily.
// can be traversed in sorted order quickly and easily.
type
ZBucket
struct
{
type
ZBucket
struct
{
*
PyPersistent
*
zodb
.
PyPersistent
next
*
ZBucket
// the bucket with the next-larger keys
next
*
ZBucket
// the bucket with the next-larger keys
keys
[]
KEY
// 'len' keys, in increasing order
keys
[]
KEY
// 'len' keys, in increasing order
...
@@ -55,7 +55,7 @@ type zBTreeItem struct {
...
@@ -55,7 +55,7 @@ type zBTreeItem struct {
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// See https://github.com/zopefoundation/BTrees/blob/4.5.0-1-gc8bf24e/BTrees/Development.txt#L198
// for details.
// for details.
type
ZBTree
struct
{
type
ZBTree
struct
{
*
PyPersistent
*
zodb
.
PyPersistent
// firstbucket points to the bucket containing the smallest key in
// firstbucket points to the bucket containing the smallest key in
// the BTree. This is found by traversing leftmost child pointers
// the BTree. This is found by traversing leftmost child pointers
...
@@ -312,10 +312,10 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
...
@@ -312,10 +312,10 @@ func (b *ZBucket) PySetState(pystate interface{}) error {
// ---- register classes to ZODB ----
// ---- register classes to ZODB ----
func
bucketNew
(
base
*
PyPersistent
)
IPyPersistent
{
return
&
ZBucket
{
PyPersistent
:
base
}
}
func
bucketNew
(
base
*
zodb
.
PyPersistent
)
zodb
.
IPyPersistent
{
return
&
ZBucket
{
PyPersistent
:
base
}
}
func
btreeNew
(
base
*
PyPersistent
)
IPyPersistent
{
return
&
ZBTree
{
PyPersistent
:
base
}
}
func
btreeNew
(
base
*
zodb
.
PyPersistent
)
zodb
.
IPyPersistent
{
return
&
ZBTree
{
PyPersistent
:
base
}
}
func
init
()
{
func
init
()
{
registerPy
Class
(
"zodb.BTree.LOBucket"
,
bucketNew
)
zodb
.
PyRegister
Class
(
"zodb.BTree.LOBucket"
,
bucketNew
)
registerPy
Class
(
"zodb.BTree.LOBtree"
,
btreeNew
)
zodb
.
PyRegister
Class
(
"zodb.BTree.LOBtree"
,
btreeNew
)
}
}
go/zodb/internal/weak/weak.go
View file @
c31c4855
...
@@ -22,8 +22,6 @@
...
@@ -22,8 +22,6 @@
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
// Package weak provides weak references for Go.
// Package weak provides weak references for Go.
//
// XXX
package
weak
package
weak
import
(
import
(
...
@@ -40,24 +38,24 @@ type iface struct {
...
@@ -40,24 +38,24 @@ type iface struct {
data
uintptr
// data
data
uintptr
// data
}
}
// weakRefState represents current state of an object
Weak
Ref points to.
// weakRefState represents current state of an object Ref points to.
type
weakRefState
int32
type
weakRefState
int32
const
(
const
(
objGot
weakRefState
=
+
1
//
Weak
Ref.Get returned !nil
objGot
weakRefState
=
+
1
// Ref.Get returned !nil
objLive
weakRefState
=
0
// object is alive, Get did not run yet in this GC cycle
objLive
weakRefState
=
0
// object is alive, Get did not run yet in this GC cycle
objReleased
weakRefState
=
-
1
// the finalizer marked object as released
objReleased
weakRefState
=
-
1
// the finalizer marked object as released
)
)
//
Weak
Ref is a weak reference.
// Ref is a weak reference.
//
//
// Create one with New
Weak
Ref and retrieve referenced object with Get.
// Create one with NewRef and retrieve referenced object with Get.
//
//
// There must be no more than 1 weak reference to any object.
// There must be no more than 1 weak reference to any object.
// Weak references must not be attached to an object on which runtime.SetFinalizer is also used.
// Weak references must not be attached to an object on which runtime.SetFinalizer is also used.
// Weak references must not be copied.
// Weak references must not be copied.
type
Weak
Ref
struct
{
type
Ref
struct
{
iface
iface
// XXX try to do without mutex and only with atomics
// XXX try to do without mutex and only with atomics
...
@@ -65,14 +63,14 @@ type WeakRef struct {
...
@@ -65,14 +63,14 @@ type WeakRef struct {
state
weakRefState
state
weakRefState
}
}
// New
Weak
Ref creates new weak reference pointing to obj.
// NewRef creates new weak reference pointing to obj.
//
//
// XXX + onrelease callback?
// XXX + onrelease callback?
func
New
WeakRef
(
obj
interface
{})
*
Weak
Ref
{
func
New
Ref
(
obj
interface
{})
*
Ref
{
// since starting from ~ Go1.4 the GC is precise, we can save interface
// since starting from ~ Go1.4 the GC is precise, we can save interface
// pointers to uintptr and that won't prevent GC from garbage
// pointers to uintptr and that won't prevent GC from garbage
// collecting the object.
// collecting the object.
w
:=
&
Weak
Ref
{
w
:=
&
Ref
{
iface
:
*
(
*
iface
)(
unsafe
.
Pointer
(
&
obj
)),
iface
:
*
(
*
iface
)(
unsafe
.
Pointer
(
&
obj
)),
state
:
objLive
,
state
:
objLive
,
}
}
...
@@ -81,7 +79,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
...
@@ -81,7 +79,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
release
=
func
(
obj
interface
{})
{
release
=
func
(
obj
interface
{})
{
// GC decided that the object is no longer reachable and
// GC decided that the object is no longer reachable and
// scheduled us to run as finalizer. During the time till we
// scheduled us to run as finalizer. During the time till we
// actually run,
Weak
Ref.Get might have been come to run and
// actually run, Ref.Get might have been come to run and
// "rematerializing" the object for use. Check if we do not
// "rematerializing" the object for use. Check if we do not
// race with any Get in progress, and reschedule us to retry at
// race with any Get in progress, and reschedule us to retry at
// next GC if we do.
// next GC if we do.
...
@@ -103,7 +101,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
...
@@ -103,7 +101,7 @@ func NewWeakRef(obj interface{}) *WeakRef {
//
//
// If original object is still alive - it is returned.
// If original object is still alive - it is returned.
// If not - nil is returned.
// If not - nil is returned.
func
(
w
*
Weak
Ref
)
Get
()
(
obj
interface
{})
{
func
(
w
*
Ref
)
Get
()
(
obj
interface
{})
{
w
.
mu
.
Lock
()
w
.
mu
.
Lock
()
if
w
.
state
!=
objReleased
{
if
w
.
state
!=
objReleased
{
w
.
state
=
objGot
w
.
state
=
objGot
...
...
go/zodb/internal/weak/weak_test.go
View file @
c31c4855
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms.
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
package
main
package
weak
import
(
import
(
"runtime"
"runtime"
...
@@ -58,7 +58,7 @@ func TestWeakRef(t *testing.T) {
...
@@ -58,7 +58,7 @@ func TestWeakRef(t *testing.T) {
type
T
struct
{
_
[
8
]
int64
}
// large enough not to go into tinyalloc
type
T
struct
{
_
[
8
]
int64
}
// large enough not to go into tinyalloc
p
:=
new
(
T
)
p
:=
new
(
T
)
w
:=
New
Weak
Ref
(
p
)
w
:=
NewRef
(
p
)
pptr
:=
uintptr
(
unsafe
.
Pointer
(
p
))
pptr
:=
uintptr
(
unsafe
.
Pointer
(
p
))
assertEq
:=
func
(
a
,
b
interface
{})
{
assertEq
:=
func
(
a
,
b
interface
{})
{
...
...
go/zodb/persistent.go
View file @
c31c4855
...
@@ -11,15 +11,15 @@
...
@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
// FOR A PARTICULAR PURPOSE
package
main
package
zodb
//
Bits that should be in ZODB XXX -> zodb
//
persistent objects.
import
(
import
(
"context"
"context"
"sync"
"sync"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb
/internal/weak
"
)
)
// IPersistent is the interface that every in-RAM object representing any database object implements.
// IPersistent is the interface that every in-RAM object representing any database object implements.
...
@@ -31,11 +31,11 @@ import (
...
@@ -31,11 +31,11 @@ import (
// but is not exactly equal to it.
// but is not exactly equal to it.
type
IPersistent
interface
{
type
IPersistent
interface
{
PJar
()
*
Connection
// Connection this in-RAM object is part of.
PJar
()
*
Connection
// Connection this in-RAM object is part of.
POid
()
zodb
.
Oid
// object ID in the database.
POid
()
Oid
// object ID in the database.
// object serial in the database as of particular Connection (PJar) view.
// object serial in the database as of particular Connection (PJar) view.
// 0 (invalid tid) if not yet loaded (XXX ok?)
// 0 (invalid tid) if not yet loaded (XXX ok?)
PSerial
()
zodb
.
Tid
PSerial
()
Tid
// PActivate brings object to live state.
// PActivate brings object to live state.
...
@@ -117,8 +117,8 @@ const (
...
@@ -117,8 +117,8 @@ const (
// Persistent is common base implementation for in-RAM representation of database objects.
// Persistent is common base implementation for in-RAM representation of database objects.
type
Persistent
struct
{
type
Persistent
struct
{
jar
*
Connection
jar
*
Connection
oid
zodb
.
Oid
oid
Oid
serial
zodb
.
Tid
serial
Tid
mu
sync
.
Mutex
mu
sync
.
Mutex
state
ObjectState
state
ObjectState
...
@@ -128,8 +128,8 @@ type Persistent struct {
...
@@ -128,8 +128,8 @@ type Persistent struct {
}
}
func
(
obj
*
Persistent
)
PJar
()
*
Connection
{
return
obj
.
jar
}
func
(
obj
*
Persistent
)
PJar
()
*
Connection
{
return
obj
.
jar
}
func
(
obj
*
Persistent
)
POid
()
zodb
.
Oid
{
return
obj
.
oid
}
func
(
obj
*
Persistent
)
POid
()
Oid
{
return
obj
.
oid
}
func
(
obj
*
Persistent
)
PSerial
()
zodb
.
Tid
{
return
obj
.
serial
}
func
(
obj
*
Persistent
)
PSerial
()
Tid
{
return
obj
.
serial
}
// loadState indicates object's load state/result.
// loadState indicates object's load state/result.
//
//
...
@@ -172,8 +172,8 @@ type Stateful interface {
...
@@ -172,8 +172,8 @@ type Stateful interface {
//
//
// XXX ^^^ better must be safe - use case: e.g. prefetch.
// XXX ^^^ better must be safe - use case: e.g. prefetch.
type
Connection
struct
{
type
Connection
struct
{
stor
zodb
.
IStorage
// underlying storage
stor
IStorage
// underlying storage
at
zodb
.
Tid
// current view of database
at
Tid
// current view of database
// {} oid -> obj
// {} oid -> obj
//
//
...
@@ -223,7 +223,7 @@ type Connection struct {
...
@@ -223,7 +223,7 @@ 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 ZBTree/ZBucket XXX verify this
// Hopefully we don't have cycles with ZBTree/ZBucket XXX verify this
objmu
sync
.
Mutex
objmu
sync
.
Mutex
objtab
map
[
zodb
.
Oid
]
*
WeakRef
// 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.
cacheControl
LiveCacheControl
cacheControl
LiveCacheControl
...
@@ -357,6 +357,6 @@ func (obj *Persistent) PInvalidate() {
...
@@ -357,6 +357,6 @@ func (obj *Persistent) PInvalidate() {
// load loads object specified by oid.
// load loads object specified by oid.
//
//
// XXX must be called ... (XXX e.g. outside transaction boundary) so that there is no race on .at .
// XXX must be called ... (XXX e.g. outside transaction boundary) so that there is no race on .at .
func
(
conn
*
Connection
)
load
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
_
*
mem
.
Buf
,
serial
zodb
.
Tid
,
_
error
)
{
func
(
conn
*
Connection
)
load
(
ctx
context
.
Context
,
oid
Oid
)
(
_
*
mem
.
Buf
,
serial
Tid
,
_
error
)
{
return
conn
.
stor
.
Load
(
ctx
,
zodb
.
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
return
conn
.
stor
.
Load
(
ctx
,
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
}
}
go/zodb/zodbpy.go
View file @
c31c4855
...
@@ -11,15 +11,15 @@
...
@@ -11,15 +11,15 @@
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE
// FOR A PARTICULAR PURPOSE
package
main
package
zodb
//
Bits that should be in ZODB XXX -> zodb
//
Support for python objects/data in ZODB.
import
(
import
(
"context"
"context"
"fmt"
"fmt"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/go123/mem"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb
/internal/weak
"
pickle
"github.com/kisielk/og-rek"
pickle
"github.com/kisielk/og-rek"
)
)
...
@@ -70,7 +70,7 @@ func (pyobj *PyPersistent) pyinstance() IPyPersistent {
...
@@ -70,7 +70,7 @@ func (pyobj *PyPersistent) pyinstance() IPyPersistent {
}
}
func
(
pyobj
*
PyPersistent
)
SetState
(
state
*
mem
.
Buf
)
error
{
func
(
pyobj
*
PyPersistent
)
SetState
(
state
*
mem
.
Buf
)
error
{
pyclass
,
pystate
,
err
:=
zodb
.
PyData
(
state
.
Data
)
.
Decode
()
pyclass
,
pystate
,
err
:=
PyData
(
state
.
Data
)
.
Decode
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
// XXX err ctx
return
err
// XXX err ctx
}
}
...
@@ -94,17 +94,17 @@ type pyClassNewFunc func(base *PyPersistent) IPyPersistent
...
@@ -94,17 +94,17 @@ type pyClassNewFunc func(base *PyPersistent) IPyPersistent
// path(pyclass) -> new(pyobj)
// path(pyclass) -> new(pyobj)
var
pyClassTab
=
make
(
map
[
string
]
pyClassNewFunc
)
var
pyClassTab
=
make
(
map
[
string
]
pyClassNewFunc
)
//
registerPy
Class registers python class to be transformed to Go instance
//
PyRegister
Class registers python class to be transformed to Go instance
// created via classNew.
// created via classNew.
//
//
// must be called from global init().
// must be called from global init().
func
registerPy
Class
(
pyClassPath
string
,
classNew
pyClassNewFunc
)
{
func
PyRegister
Class
(
pyClassPath
string
,
classNew
pyClassNewFunc
)
{
pyClassTab
[
pyClassPath
]
=
classNew
pyClassTab
[
pyClassPath
]
=
classNew
// XXX + register so that
zodb.
PyData decode handles pyClassPath
// XXX + register so that PyData decode handles pyClassPath
}
}
// newGhost creates new ghost object corresponding to pyclass and oid.
// newGhost creates new ghost object corresponding to pyclass and oid.
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
IPyPersistent
{
func
(
conn
*
Connection
)
newGhost
(
pyclass
pickle
.
Class
,
oid
Oid
)
IPyPersistent
{
pyobj
:=
&
PyPersistent
{
pyobj
:=
&
PyPersistent
{
Persistent
:
Persistent
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
,
state
:
GHOST
},
Persistent
:
Persistent
{
jar
:
conn
,
oid
:
oid
,
serial
:
0
,
state
:
GHOST
},
pyclass
:
pyclass
,
pyclass
:
pyclass
,
...
@@ -151,7 +151,7 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
...
@@ -151,7 +151,7 @@ func (d *dummyPyInstance) PySetState(pystate interface{}) error {
//
//
// The object's data is not neccessarily loaded after Get returns. Use
// The object's data is not neccessarily loaded after Get returns. Use
// PActivate to make sure the object ifs fully loaded.
// PActivate to make sure the object ifs fully loaded.
func
(
conn
*
Connection
)
Get
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
IPyPersistent
,
error
)
{
func
(
conn
*
Connection
)
Get
(
ctx
context
.
Context
,
oid
Oid
)
(
IPyPersistent
,
error
)
{
conn
.
objmu
.
Lock
()
// XXX -> rlock
conn
.
objmu
.
Lock
()
// XXX -> rlock
wobj
:=
conn
.
objtab
[
oid
]
wobj
:=
conn
.
objtab
[
oid
]
var
xobj
interface
{}
var
xobj
interface
{}
...
@@ -205,7 +205,7 @@ func (e *wrongClassError) Error() string {
...
@@ -205,7 +205,7 @@ func (e *wrongClassError) Error() string {
//
//
// Use-case: in ZODB references are (pyclass, oid), so new ghost is created
// Use-case: in ZODB references are (pyclass, oid), so new ghost is created
// without further loading anything.
// without further loading anything.
func
(
conn
*
Connection
)
get
(
pyclass
pickle
.
Class
,
oid
zodb
.
Oid
)
(
IPyPersistent
,
error
)
{
func
(
conn
*
Connection
)
get
(
pyclass
pickle
.
Class
,
oid
Oid
)
(
IPyPersistent
,
error
)
{
conn
.
objmu
.
Lock
()
// XXX -> rlock
conn
.
objmu
.
Lock
()
// XXX -> rlock
wobj
:=
conn
.
objtab
[
oid
]
wobj
:=
conn
.
objtab
[
oid
]
var
pyobj
IPyPersistent
var
pyobj
IPyPersistent
...
@@ -217,7 +217,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
...
@@ -217,7 +217,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
}
}
if
pyobj
==
nil
{
if
pyobj
==
nil
{
pyobj
=
conn
.
newGhost
(
pyclass
,
oid
)
pyobj
=
conn
.
newGhost
(
pyclass
,
oid
)
conn
.
objtab
[
oid
]
=
NewWeak
Ref
(
pyobj
)
conn
.
objtab
[
oid
]
=
weak
.
New
Ref
(
pyobj
)
}
else
{
}
else
{
checkClass
=
true
checkClass
=
true
}
}
...
@@ -225,7 +225,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
...
@@ -225,7 +225,7 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
if
checkClass
{
if
checkClass
{
if
cls
:=
pyobj
.
PyClass
();
pyclass
!=
cls
{
if
cls
:=
pyobj
.
PyClass
();
pyclass
!=
cls
{
return
nil
,
&
zodb
.
OpError
{
return
nil
,
&
OpError
{
URL
:
conn
.
stor
.
URL
(),
URL
:
conn
.
stor
.
URL
(),
Op
:
fmt
.
Sprintf
(
"@%s: get"
,
conn
.
at
),
// XXX abuse
Op
:
fmt
.
Sprintf
(
"@%s: get"
,
conn
.
at
),
// XXX abuse
Args
:
oid
,
Args
:
oid
,
...
@@ -241,15 +241,15 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
...
@@ -241,15 +241,15 @@ func (conn *Connection) get(pyclass pickle.Class, oid zodb.Oid) (IPyPersistent,
//
//
// loadpy does not create any in-RAM object associated with Connection.
// loadpy does not create any in-RAM object associated with Connection.
// It only returns decoded database data.
// It only returns decoded database data.
func
(
conn
*
Connection
)
loadpy
(
ctx
context
.
Context
,
oid
zodb
.
Oid
)
(
pyclass
pickle
.
Class
,
pystate
interface
{},
serial
zodb
.
Tid
,
_
error
)
{
func
(
conn
*
Connection
)
loadpy
(
ctx
context
.
Context
,
oid
Oid
)
(
pyclass
pickle
.
Class
,
pystate
interface
{},
serial
Tid
,
_
error
)
{
buf
,
serial
,
err
:=
conn
.
stor
.
Load
(
ctx
,
zodb
.
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
buf
,
serial
,
err
:=
conn
.
stor
.
Load
(
ctx
,
Xid
{
Oid
:
oid
,
At
:
conn
.
at
})
if
err
!=
nil
{
if
err
!=
nil
{
return
pickle
.
Class
{},
nil
,
0
,
err
return
pickle
.
Class
{},
nil
,
0
,
err
}
}
defer
buf
.
Release
()
defer
buf
.
Release
()
pyclass
,
pystate
,
err
=
zodb
.
PyData
(
buf
.
Data
)
.
Decode
()
pyclass
,
pystate
,
err
=
PyData
(
buf
.
Data
)
.
Decode
()
if
err
!=
nil
{
if
err
!=
nil
{
return
pickle
.
Class
{},
nil
,
0
,
err
// XXX err ctx
return
pickle
.
Class
{},
nil
,
0
,
err
// XXX err ctx
}
}
...
...
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