Commit 9b44fc23 authored by Kirill Smelkov's avatar Kirill Smelkov

X Unfortunately it crashes in GC even with weak.Ref reworked to be one word instead of two

    ---- 8< ----
    (z-dev) kirr@deca:~/src/wendelin/wendelin.core/wcfs$ time ./gogccrash 2>&1

    done, crashes:
    BUG/2/core

    Завершено

    real    28m54,016s
    user    30m27,968s
    sys     7m35,028s

    (z-dev) kirr@deca:~/src/wendelin/wendelin.core/wcfs$ cat BUG/2/log

    ...

    runtime: full=0xc0001f10000005 next=205 jobs=204 nDataRoots=1 nBSSRoots=1 nSpanRoots=16 nStackRoots=184
    panic: non-empty mark queue after concurrent mark
    fatal error: panic on system stack

    ...
    ---- 8< ----
parent 451d1e3f
This diff is collapsed.
This diff is collapsed.
module lab.nexedi.com/nexedi/wendelin.core/wcfs module lab.nexedi.com/nexedi/wendelin.core/wcfs
go 1.14 go 1.18
require ( require (
github.com/kisielk/og-rek v1.0.1-0.20180928202415-8b25c4cefd6c github.com/kisielk/og-rek v1.0.1-0.20180928202415-8b25c4cefd6c
lab.nexedi.com/kirr/go123 v0.0.0-20200916121347-316617668e12 lab.nexedi.com/kirr/go123 v0.0.0-20200916121347-316617668e12
lab.nexedi.com/kirr/neo/go v0.0.0-20201012044742-28494187df87 lab.nexedi.com/kirr/neo/go v0.0.0-20201012044742-28494187df87
) )
// indirects
require (
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537
github.com/DataDog/czlib v0.0.0-20160811164712-4bc9a24e37f2
github.com/fsnotify/fsnotify v1.4.10-0.20200417215612-7f4cf4dd2b52
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/philhofer/fwd v1.0.0
github.com/pkg/errors v0.9.1
github.com/someonegg/gocontainer v1.0.0
github.com/shamaton/msgpack v1.1.1
github.com/tinylib/msgp v1.1.3-0.20200327023543-e88e92c0ccca
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
)
...@@ -117,7 +117,7 @@ type LiveCache struct { ...@@ -117,7 +117,7 @@ type LiveCache 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.
objtab map[Oid]*weak.Ref // oid -> weak.Ref(IPersistent) objtab map[Oid]*weak.Ref[Persistent] // oid -> weak.Ref(IPersistent)
// hooks for application to influence live caching decisions. // hooks for application to influence live caching decisions.
control LiveCacheControl control LiveCacheControl
...@@ -184,7 +184,7 @@ func newConnection(db *DB, at Tid) *Connection { ...@@ -184,7 +184,7 @@ func newConnection(db *DB, at Tid) *Connection {
at: at, at: at,
cache: LiveCache{ cache: LiveCache{
pinned: make(map[Oid]IPersistent), pinned: make(map[Oid]IPersistent),
objtab: make(map[Oid]*weak.Ref), objtab: make(map[Oid]*weak.Ref[Persistent]),
}, },
} }
} }
...@@ -231,7 +231,7 @@ func (cache *LiveCache) Get(oid Oid) IPersistent { ...@@ -231,7 +231,7 @@ func (cache *LiveCache) Get(oid Oid) IPersistent {
wobj := cache.objtab[oid] wobj := cache.objtab[oid]
if wobj != nil { if wobj != nil {
if xobj := wobj.Get(); xobj != nil { if xobj := wobj.Get(); xobj != nil {
obj = xobj.(IPersistent) obj = xobj.instance
} }
} }
...@@ -252,7 +252,7 @@ func (cache *LiveCache) setNew(oid Oid, obj IPersistent) { ...@@ -252,7 +252,7 @@ func (cache *LiveCache) setNew(oid Oid, obj IPersistent) {
cache.pinned[oid] = obj cache.pinned[oid] = obj
// XXX assert .objtab[oid] == nil ? // XXX assert .objtab[oid] == nil ?
} else { } else {
cache.objtab[oid] = weak.NewRef(obj) cache.objtab[oid] = weak.NewRef(obj.persistent())
// XXX assert .pinned[oid] == nil ? // XXX assert .pinned[oid] == nil ?
} }
} }
...@@ -264,7 +264,7 @@ func (cache *LiveCache) forEach(f func(IPersistent)) { ...@@ -264,7 +264,7 @@ func (cache *LiveCache) forEach(f func(IPersistent)) {
} }
for _, wobj := range cache.objtab { for _, wobj := range cache.objtab {
if xobj := wobj.Get(); xobj != nil { if xobj := wobj.Get(); xobj != nil {
f(xobj.(IPersistent)) f(xobj.instance)
} }
} }
} }
...@@ -280,7 +280,7 @@ func (cache *LiveCache) SetControl(c LiveCacheControl) { ...@@ -280,7 +280,7 @@ func (cache *LiveCache) SetControl(c LiveCacheControl) {
// reclassify all objects // reclassify all objects
c2 := *cache c2 := *cache
cache.objtab = make(map[Oid]*weak.Ref) cache.objtab = make(map[Oid]*weak.Ref[Persistent])
cache.pinned = make(map[Oid]IPersistent) cache.pinned = make(map[Oid]IPersistent)
c2.forEach(func(obj IPersistent) { c2.forEach(func(obj IPersistent) {
cache.setNew(obj.POid(), obj) cache.setNew(obj.POid(), obj)
......
...@@ -31,9 +31,10 @@ import ( ...@@ -31,9 +31,10 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"unsafe" "unsafe"
"math/rand" // "math/rand"
) )
/*
// iface is how Go runtime represents an interface. // iface is how Go runtime represents an interface.
// //
// NOTE layout must be synchronized to Go runtime representation. // NOTE layout must be synchronized to Go runtime representation.
...@@ -42,6 +43,7 @@ type iface struct { ...@@ -42,6 +43,7 @@ type iface struct {
typ uintptr // type typ uintptr // type
data uintptr // data data uintptr // data
} }
*/
// weakRefState represents current state of an object Ref points to. // weakRefState represents current state of an object Ref points to.
type weakRefState int32 type weakRefState int32
...@@ -60,8 +62,10 @@ const ( ...@@ -60,8 +62,10 @@ const (
// 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 Ref struct { type Ref[T any] struct {
iface // iface
// XXX only one word + reference to go memory model
iptr uintptr // XXX NOTE correctness depends on non-moving property of Go GC
// XXX try to do without mutex and only with atomics // XXX try to do without mutex and only with atomics
mu sync.Mutex mu sync.Mutex
...@@ -71,12 +75,13 @@ type Ref struct { ...@@ -71,12 +75,13 @@ type Ref struct {
// NewRef creates new weak reference pointing to obj. // NewRef creates new weak reference pointing to obj.
// //
// TODO + onrelease callback? // TODO + onrelease callback?
func NewRef(obj interface{}) *Ref { func NewRef[T any](obj *T) *Ref[T] {
// 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 := &Ref{ w := &Ref[T]{
iface: *(*iface)(unsafe.Pointer(&obj)), // iface: *(*iface)(unsafe.Pointer(&obj)),
iptr: (uintptr)(unsafe.Pointer(obj)),
state: objLive, state: objLive,
} }
...@@ -85,10 +90,11 @@ func NewRef(obj interface{}) *Ref { ...@@ -85,10 +90,11 @@ func NewRef(obj interface{}) *Ref {
return w return w
} }
func (w *Ref) release(obj interface{}) { func (w *Ref[T]) release(obj *T) {
ifobj := *(*iface)(unsafe.Pointer(&obj)) // ifobj := *(*iface)(unsafe.Pointer(&obj))
if w.iface != ifobj { iptr := (uintptr)(unsafe.Pointer(obj))
panic(fmt.Sprintf("weak: release: w.iface != obj; w.iface=%x obj=%x", w.iface, ifobj)) if w.iptr != iptr {
panic(fmt.Sprintf("weak: release: w.iptr != obj; w.iptr=%x obj=%x", w.iptr, iptr))
} }
// GC decided that the object is no longer reachable and // GC decided that the object is no longer reachable and
...@@ -115,7 +121,7 @@ var xxx uint64 ...@@ -115,7 +121,7 @@ var xxx uint64
// //
// 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 *Ref) Get() (obj interface{}) { func (w *Ref[T]) Get() (obj *T) {
w.mu.Lock() w.mu.Lock()
if w.state != objReleased { if w.state != objReleased {
w.state = objGot w.state = objGot
...@@ -123,6 +129,13 @@ func (w *Ref) Get() (obj interface{}) { ...@@ -123,6 +129,13 @@ func (w *Ref) Get() (obj interface{}) {
//time.Sleep(100*time.Nanosecond) //time.Sleep(100*time.Nanosecond)
// recreate interface{} from saved words. // recreate interface{} from saved words.
// XXX do writes as pointers so that compiler emits write barriers to notify GC? // XXX do writes as pointers so that compiler emits write barriers to notify GC?
// recreate pointer from saved word.
obj = (*T)(unsafe.Pointer(w.iptr))
atomic.AddUint64(&xxx, 1) // barrier
time.Sleep(100*time.Nanosecond)
/*
i := (*iface)(unsafe.Pointer(&obj)) i := (*iface)(unsafe.Pointer(&obj))
//*i = w.iface //*i = w.iface
...@@ -150,6 +163,7 @@ func (w *Ref) Get() (obj interface{}) { ...@@ -150,6 +163,7 @@ func (w *Ref) Get() (obj interface{}) {
} else { } else {
i.data = w.iface.data i.data = w.iface.data
} }
*/
} }
w.mu.Unlock() w.mu.Unlock()
......
# github.com/DataDog/czlib v0.0.0-20160811164712-4bc9a24e37f2 # github.com/DataDog/czlib v0.0.0-20160811164712-4bc9a24e37f2
github.com/DataDog/czlib github.com/DataDog/czlib
## explicit
# github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 # github.com/cznic/strutil v0.0.0-20181122101858-275e90344537
github.com/cznic/strutil github.com/cznic/strutil
## explicit
# github.com/fsnotify/fsnotify v1.4.10-0.20200417215612-7f4cf4dd2b52 # github.com/fsnotify/fsnotify v1.4.10-0.20200417215612-7f4cf4dd2b52
github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify
## explicit
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b # github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/glog github.com/golang/glog
## explicit
# github.com/kisielk/og-rek v1.0.1-0.20180928202415-8b25c4cefd6c # github.com/kisielk/og-rek v1.0.1-0.20180928202415-8b25c4cefd6c
## explicit ## explicit
github.com/kisielk/og-rek github.com/kisielk/og-rek
# github.com/philhofer/fwd v1.0.0 # github.com/philhofer/fwd v1.0.0
github.com/philhofer/fwd github.com/philhofer/fwd
## explicit
# github.com/pkg/errors v0.9.1 # github.com/pkg/errors v0.9.1
github.com/pkg/errors github.com/pkg/errors
## explicit
# github.com/shamaton/msgpack v1.1.1 # github.com/shamaton/msgpack v1.1.1
## explicit
github.com/shamaton/msgpack github.com/shamaton/msgpack
github.com/shamaton/msgpack/def github.com/shamaton/msgpack/def
github.com/shamaton/msgpack/ext github.com/shamaton/msgpack/ext
...@@ -23,9 +30,12 @@ github.com/shamaton/msgpack/internal/encoding ...@@ -23,9 +30,12 @@ github.com/shamaton/msgpack/internal/encoding
github.com/shamaton/msgpack/time github.com/shamaton/msgpack/time
# github.com/someonegg/gocontainer v1.0.0 # github.com/someonegg/gocontainer v1.0.0
github.com/someonegg/gocontainer/rbuf github.com/someonegg/gocontainer/rbuf
## explicit
# github.com/tinylib/msgp v1.1.3-0.20200327023543-e88e92c0ccca # github.com/tinylib/msgp v1.1.3-0.20200327023543-e88e92c0ccca
github.com/tinylib/msgp/msgp github.com/tinylib/msgp/msgp
## explicit
# golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 # golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
## explicit
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
# lab.nexedi.com/kirr/go123 v0.0.0-20200916121347-316617668e12 # lab.nexedi.com/kirr/go123 v0.0.0-20200916121347-316617668e12
## explicit ## explicit
...@@ -48,7 +58,7 @@ lab.nexedi.com/kirr/go123/xruntime ...@@ -48,7 +58,7 @@ lab.nexedi.com/kirr/go123/xruntime
lab.nexedi.com/kirr/go123/xstrings lab.nexedi.com/kirr/go123/xstrings
lab.nexedi.com/kirr/go123/xsync lab.nexedi.com/kirr/go123/xsync
# lab.nexedi.com/kirr/neo/go v0.0.0-20201012044742-28494187df87 # lab.nexedi.com/kirr/neo/go v0.0.0-20201012044742-28494187df87
## explicit ## explicit; go 1.18
lab.nexedi.com/kirr/neo/go/internal/log lab.nexedi.com/kirr/neo/go/internal/log
lab.nexedi.com/kirr/neo/go/internal/packed lab.nexedi.com/kirr/neo/go/internal/packed
lab.nexedi.com/kirr/neo/go/internal/task lab.nexedi.com/kirr/neo/go/internal/task
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment