func (cc copyContext) init() copyContext { if cc.copies == nil { return copyContext{ copies: rbtree.NewTree(compare), } } return cc }
func NewNonceRegistry(tsrc TimeSource) *NonceRegistry { return &NonceRegistry{ TSrc: tsrc, TimeTree: rbtree.NewTree(func(a, b rbtree.Item) int { return int(a.(*Job).Sendtime - b.(*Job).Sendtime) }), NonceHash: make(map[Nonce]Ntm), InvalidAfterDur: Ntm(3600e9), // 1 hour (in nanoseconds) } }
func (destSeg *Segment) writePtr(off int, src Object, copies *rbtree.Tree, depth int) error { // handle size-zero Objects/empty structs if src.Segment == nil { return nil } srcSeg := src.Segment if src.typ == TypeNull || isEmptyStruct(src) { binary.LittleEndian.PutUint64(destSeg.Data[off:], 0) return nil } else if destSeg == srcSeg { // Same segment binary.LittleEndian.PutUint64(destSeg.Data[off:], src.value(off)) return nil } else if destSeg.Message != srcSeg.Message || (src.flags&isListMember) != 0 || (src.flags&isBitListMember) != 0 { // We need to clone the target. if depth >= 32 { return ErrCopyDepth } // First see if the ptr has already been copied if copies == nil { copies = rbtree.NewTree(compare) } key := offset{ id: srcSeg.Id, boff: int64(src.off) * 8, bend: int64(src.dataEnd()) * 8, newval: Object{ typ: src.typ, length: src.length, datasz: src.datasz, ptrs: src.ptrs, flags: (src.flags & isCompositeList), }, } if (src.flags & isBitListMember) != 0 { key.boff += int64(src.flags & bitOffsetMask) key.bend = key.boff + 1 key.newval.datasz = 8 } if (src.flags & isCompositeList) != 0 { key.boff -= 64 // Q: what the heck does this do? why is it here? A: Accounts for the Tag word, perhaps because dataEnd() does not. } iter := copies.FindLE(key) if key.bend > key.boff { if !iter.NegativeLimit() { other := iter.Item().(offset) if key.id == other.id { if key.boff == other.boff && key.bend == other.bend { return destSeg.writePtr(off, other.newval, nil, depth+1) } else if other.bend >= key.bend { return ErrOverlap } } } iter = iter.Next() if !iter.Limit() { other := iter.Item().(offset) if key.id == other.id && other.boff < key.bend { return ErrOverlap } } } // No copy nor overlap found, so we need to clone the target n, err := destSeg.create(int((key.bend-key.boff)/8), key.newval) if err != nil { return err } // n is possibly in a new segment, if destSeg was full. newSeg := n.Segment if (n.flags & isCompositeList) != 0 { copy(newSeg.Data[n.off:], srcSeg.Data[src.off-8:src.off]) n.off += 8 } key.newval = n copies.Insert(key) //fmt.Printf(" ..... need to clone target: key.newval: %#v of type '%s'\n", key.newval, key.newval.typ.String()) switch src.typ { case TypeStruct: if (src.flags & isBitListMember) != 0 { if (srcSeg.Data[src.off] & (1 << (src.flags & bitOffsetMask))) != 0 { newSeg.Data[n.off] = 1 } else { newSeg.Data[n.off] = 0 } for i := range newSeg.Data[n.off+1 : n.off+8] { newSeg.Data[i] = 0 } } else { dest := Object{ Segment: newSeg, off: n.off, datasz: n.datasz, ptrs: n.ptrs, } if err := copyStructHandlingVersionSkew(dest, src, copies, depth, 0, 0); err != nil { return err } } case TypeList: // recognize Data and Text, both List(Byte), as special cases for speed. if n.datasz == 1 && n.ptrs == 0 && src.datasz == 1 && src.ptrs == 0 { //fmt.Printf("\n\n *** special case for Text and Data kicking in *** \n\n") copy(newSeg.Data[n.off:], srcSeg.Data[src.off:src.off+n.length]) break } dest := Object{ Segment: newSeg, off: n.off, datasz: n.datasz, ptrs: n.ptrs, } for i := 0; i < n.length; i++ { if err := copyStructHandlingVersionSkew(dest, src, copies, depth, i, i); err != nil { return err } } case TypePointerList: for i := 0; i < n.length; i++ { c := srcSeg.readPtr(src.off + i*8) if err := newSeg.writePtr(n.off+i*8, c, copies, depth+1); err != nil { return err } } case TypeBitList: copy(newSeg.Data[n.off:], srcSeg.Data[src.off:src.off+src.datasz]) } return destSeg.writePtr(off, key.newval, nil, depth+1) } else if (src.flags & hasPointerTag) != 0 { // By lucky chance, the data has a tag in front of it. This // happens when create had to move the data to a new segment. binary.LittleEndian.PutUint64(destSeg.Data[off:], srcSeg.farPtrValue(farPointer, src.off-8)) return nil } else if len(srcSeg.Data)+8 <= cap(srcSeg.Data) { // Have room in the target for a tag binary.LittleEndian.PutUint64(srcSeg.Data[len(srcSeg.Data):], src.value(len(srcSeg.Data))) binary.LittleEndian.PutUint64(destSeg.Data[off:], srcSeg.farPtrValue(farPointer, len(srcSeg.Data))) srcSeg.Data = srcSeg.Data[:len(srcSeg.Data)+8] return nil } else { // Need to create a double far pointer. Try and create it in // the originating segment if we can. t := destSeg if len(t.Data)+16 > cap(t.Data) { var err error if t, err = t.Message.NewSegment(16); err != nil { return err } } binary.LittleEndian.PutUint64(t.Data[len(t.Data):], srcSeg.farPtrValue(farPointer, src.off)) binary.LittleEndian.PutUint64(t.Data[len(t.Data)+8:], src.value(src.off-8)) binary.LittleEndian.PutUint64(destSeg.Data[off:], t.farPtrValue(doubleFarPointer, len(t.Data))) t.Data = t.Data[:len(t.Data)+16] return nil } }