Example #1
0
func (cc copyContext) init() copyContext {
	if cc.copies == nil {
		return copyContext{
			copies: rbtree.NewTree(compare),
		}
	}
	return cc
}
Example #2
0
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)
	}

}
Example #3
0
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
	}
}