func (hca highContentionAllocator) allocate(tr fdb.Transaction, s subspace.Subspace) (subspace.Subspace, error) { rr := tr.Snapshot().GetRange(hca.counters, fdb.RangeOptions{Limit: 1, Reverse: true}) kvs := rr.GetSliceOrPanic() var start, count int64 if len(kvs) == 1 { t, e := hca.counters.Unpack(kvs[0].Key) if e != nil { return nil, e } start = t[0].(int64) e = binary.Read(bytes.NewBuffer(kvs[0].Value), binary.LittleEndian, &count) if e != nil { return nil, e } } window := windowSize(start) if (count+1)*2 >= window { // Advance the window tr.ClearRange(fdb.KeyRange{hca.counters, append(hca.counters.Sub(start).FDBKey(), 0x00)}) start += window tr.ClearRange(fdb.KeyRange{hca.recent, hca.recent.Sub(start)}) window = windowSize(start) } // Increment the allocation count for the current window tr.Add(hca.counters.Sub(start), oneBytes) for { // As of the snapshot being read from, the window is less than half // full, so this should be expected to take 2 tries. Under high // contention (and when the window advances), there is an additional // subsequent risk of conflict for this transaction. candidate := rand.Int63n(window) + start key := hca.recent.Sub(candidate) if tr.Get(key).MustGet() == nil { tr.Set(key, []byte("")) return s.Sub(candidate), nil } } }