@@ -63,8 +63,10 @@ type Ctrie struct {
63
63
}
64
64
65
65
// generation demarcates Ctrie snapshots. We use a heap-allocated reference
66
- // instead of an integer to avoid integer overflows.
67
- type generation struct {}
66
+ // instead of an integer to avoid integer overflows. Struct must have a field
67
+ // on it since two distinct zero-size variables may have the same address in
68
+ // memory.
69
+ type generation struct { _ int }
68
70
69
71
// iNode is an indirection node. I-nodes remain present in the Ctrie even as
70
72
// nodes above and below change. Thread-safety is achieved in part by
@@ -320,7 +322,7 @@ func (c *Ctrie) Snapshot() *Ctrie {
320
322
root := c .readRoot ()
321
323
main := gcasRead (root , c )
322
324
if c .rdcssRoot (root , main , root .copyToGen (& generation {}, c )) {
323
- return newCtrie (root .copyToGen (& generation {}, c ), c .hashFactory , c .readOnly )
325
+ return newCtrie (c . readRoot () .copyToGen (& generation {}, c ), c .hashFactory , c .readOnly )
324
326
}
325
327
}
326
328
}
@@ -335,7 +337,7 @@ func (c *Ctrie) ReadOnlySnapshot() *Ctrie {
335
337
root := c .readRoot ()
336
338
main := gcasRead (root , c )
337
339
if c .rdcssRoot (root , main , root .copyToGen (& generation {}, c )) {
338
- return newCtrie (root , c .hashFactory , true )
340
+ return newCtrie (c . readRoot () , c .hashFactory , true )
339
341
}
340
342
}
341
343
}
@@ -363,7 +365,7 @@ func (c *Ctrie) Iterator(cancel <-chan struct{}) <-chan *Entry {
363
365
ch := make (chan * Entry )
364
366
snapshot := c .ReadOnlySnapshot ()
365
367
go func () {
366
- traverse (snapshot .root , ch , cancel )
368
+ snapshot . traverse (snapshot .readRoot () , ch , cancel )
367
369
close (ch )
368
370
}()
369
371
return ch
@@ -385,13 +387,14 @@ func (c *Ctrie) Size() uint {
385
387
386
388
var errCanceled = errors .New ("canceled" )
387
389
388
- func traverse (i * iNode , ch chan <- * Entry , cancel <- chan struct {}) error {
390
+ func (c * Ctrie ) traverse (i * iNode , ch chan <- * Entry , cancel <- chan struct {}) error {
391
+ main := gcasRead (i , c )
389
392
switch {
390
- case i . main .cNode != nil :
391
- for _ , br := range i . main .cNode .array {
393
+ case main .cNode != nil :
394
+ for _ , br := range main .cNode .array {
392
395
switch b := br .(type ) {
393
396
case * iNode :
394
- if err := traverse (b , ch , cancel ); err != nil {
397
+ if err := c . traverse (b , ch , cancel ); err != nil {
395
398
return err
396
399
}
397
400
case * sNode :
@@ -402,8 +405,8 @@ func traverse(i *iNode, ch chan<- *Entry, cancel <-chan struct{}) error {
402
405
}
403
406
}
404
407
}
405
- case i . main .lNode != nil :
406
- for _ , e := range i . main .lNode .Map (func (sn interface {}) interface {} {
408
+ case main .lNode != nil :
409
+ for _ , e := range main .lNode .Map (func (sn interface {}) interface {} {
407
410
return sn .(* sNode ).Entry
408
411
}) {
409
412
select {
@@ -485,7 +488,7 @@ func (c *Ctrie) iinsert(i *iNode, entry *Entry, lev uint, parent *iNode, startGe
485
488
// If the branch is an I-node, then iinsert is called recursively.
486
489
in := branch .(* iNode )
487
490
if startGen == in .gen {
488
- return c .iinsert (in , entry , lev + w , i , i . gen )
491
+ return c .iinsert (in , entry , lev + w , i , startGen )
489
492
}
490
493
if gcas (i , main , & mainNode {cNode : cn .renewed (startGen , c )}, c ) {
491
494
return c .iinsert (i , entry , lev , parent , startGen )
@@ -810,8 +813,8 @@ func gcasComplete(i *iNode, m *mainNode, ctrie *Ctrie) *mainNode {
810
813
// Signals GCAS failure. Swap old value back into I-node.
811
814
fn := prev .failed
812
815
if atomic .CompareAndSwapPointer ((* unsafe .Pointer )(unsafe .Pointer (& i .main )),
813
- unsafe .Pointer (m ), unsafe .Pointer (fn . prev )) {
814
- return fn . prev
816
+ unsafe .Pointer (m ), unsafe .Pointer (fn )) {
817
+ return fn
815
818
}
816
819
m = (* mainNode )(atomic .LoadPointer (
817
820
(* unsafe .Pointer )(unsafe .Pointer (& i .main ))))
@@ -845,7 +848,7 @@ type rdcssDescriptor struct {
845
848
old * iNode
846
849
expected * mainNode
847
850
nv * iNode
848
- committed bool
851
+ committed int32
849
852
}
850
853
851
854
// readRoot performs a linearizable read of the Ctrie root. This operation is
@@ -878,7 +881,7 @@ func (c *Ctrie) rdcssRoot(old *iNode, expected *mainNode, nv *iNode) bool {
878
881
}
879
882
if c .casRoot (old , desc ) {
880
883
c .rdcssComplete (false )
881
- return desc .rdcss .committed
884
+ return atomic . LoadInt32 ( & desc .rdcss .committed ) == 1
882
885
}
883
886
return false
884
887
}
@@ -909,7 +912,7 @@ func (c *Ctrie) rdcssComplete(abort bool) *iNode {
909
912
if oldeMain == exp {
910
913
// Commit the RDCSS.
911
914
if c .casRoot (r , nv ) {
912
- desc .committed = true
915
+ atomic . StoreInt32 ( & desc .committed , 1 )
913
916
return nv
914
917
}
915
918
continue
0 commit comments