Stack allocate return from rbf.Tx.cursor()

This commit is contained in:
Ben Johnson 2020-09-10 14:58:22 -06:00
parent be944a6247
commit 5b72a68628
3 changed files with 57 additions and 64 deletions

View file

@ -1015,8 +1015,8 @@ func TestCursor_PlayContainer(t *testing.T) {
}
cur, _ := tx.Cursor("x")
offset := uint64(0)
many(cur, 0, rbf.ArrayMaxSize+offset)
many(cur, 65536, rbf.ArrayMaxSize+offset)
many(&cur, 0, rbf.ArrayMaxSize+offset)
many(&cur, 65536, rbf.ArrayMaxSize+offset)
/*
many(cur, 2*65536, rbf.ArrayMaxSize+offset)
many(cur, 3*65536, rbf.ArrayMaxSize) //+offset)

View file

@ -502,10 +502,10 @@ func (tx *Tx) Remove(name string, a ...uint64) (changeCount int, err error) {
}
c, err := tx.cursor(name)
if err != nil {
return 0, err
} else if c == nil {
if err == ErrBitmapNotFound {
return 0, nil
} else if err != nil {
return 0, err
}
for _, v := range a {
if vchanged, err := c.Remove(v); err != nil {
@ -529,38 +529,36 @@ func (tx *Tx) Contains(name string, v uint64) (bool, error) {
}
c, err := tx.cursor(name)
if err != nil {
return false, err
} else if c == nil {
if err == ErrBitmapNotFound {
return false, nil
} else if err != nil {
return false, err
}
return c.Contains(v)
}
// Cursor returns an instance of a cursor this bitmap.
func (tx *Tx) Cursor(name string) (*Cursor, error) {
func (tx *Tx) Cursor(name string) (Cursor, error) {
tx.mu.RLock()
defer tx.mu.RUnlock()
return tx.cursor(name)
}
func (tx *Tx) cursor(name string) (*Cursor, error) {
func (tx *Tx) cursor(name string) (Cursor, error) {
if tx.db == nil {
return nil, ErrTxClosed
return Cursor{}, ErrTxClosed
} else if name == "" {
return nil, ErrBitmapNameRequired
return Cursor{}, ErrBitmapNameRequired
}
root, err := tx.root(name)
if err == ErrBitmapNotFound {
return nil, nil
} else if err != nil {
return nil, err
if err != nil {
return Cursor{}, err
}
c := Cursor{tx: tx}
c.stack.elems[0] = stackElem{pgno: root}
return &c, nil
return c, nil
}
// RoaringBitmap returns a bitmap as a Roaring bitmap.
@ -575,10 +573,10 @@ func (tx *Tx) RoaringBitmap(name string) (*roaring.Bitmap, error) {
}
c, err := tx.cursor(name)
if err != nil {
return nil, err
} else if c == nil {
if err == ErrBitmapNotFound {
return roaring.NewSliceBitmap(), nil
} else if err != nil {
return nil, err
}
other := roaring.NewSliceBitmap()
@ -615,9 +613,9 @@ func (tx *Tx) container(name string, key uint64) (*roaring.Container, error) {
}
c, err := tx.cursor(name)
if err != nil {
return nil, err
} else if c == nil {
if err == ErrBitmapNotFound {
return nil, nil
} else if err != nil {
return nil, err
} else if exact, err := c.Seek(key); err != nil || !exact {
return nil, err
@ -671,10 +669,10 @@ func (tx *Tx) RemoveContainer(name string, key uint64) error {
func (tx *Tx) removeContainer(name string, key uint64) error {
c, err := tx.cursor(name)
if err != nil {
return err
} else if c == nil {
if err == ErrBitmapNotFound {
return nil
} else if err != nil {
return err
} else if exact, err := c.Seek(key); err != nil || !exact {
return err
}
@ -1007,14 +1005,12 @@ func (tx *Tx) ContainerIterator(name string, key uint64) (citer roaring.Containe
defer tx.mu.RUnlock()
c, err := tx.cursor(name)
if c == nil && err == nil {
if err == ErrBitmapNotFound {
return &emptyContainerIterator{}, false, nil // nothing available.
} else if err != nil {
return nil, false, err
}
// INVAR: c is not nil
exact, err := c.Seek(key)
if err != nil {
return nil, false, err
@ -1031,10 +1027,10 @@ func (tx *Tx) ForEachRange(name string, start, end uint64, fn func(uint64) error
defer tx.mu.RUnlock()
c, err := tx.cursor(name)
if err != nil {
return err
} else if c == nil {
if err == ErrBitmapNotFound {
return nil
} else if err != nil {
return err
} else if _, err := c.Seek(highbits(start)); err != nil {
return err
}
@ -1099,10 +1095,10 @@ func (tx *Tx) Count(name string) (uint64, error) {
defer tx.mu.RUnlock()
c, err := tx.cursor(name)
if err != nil {
return 0, err
} else if c == nil {
if err == ErrBitmapNotFound {
return 0, nil
} else if err != nil {
return 0, err
} else if err := c.First(); err != nil {
return 0, err
}
@ -1125,10 +1121,10 @@ func (tx *Tx) Max(name string) (uint64, error) {
defer tx.mu.RUnlock()
c, err := tx.cursor(name)
if err != nil {
return 0, err
} else if c == nil {
if err == ErrBitmapNotFound {
return 0, nil
} else if err != nil {
return 0, err
} else if err := c.Last(); err == io.EOF {
return 0, nil
} else if err != nil {
@ -1144,10 +1140,10 @@ func (tx *Tx) Min(name string) (uint64, bool, error) {
defer tx.mu.RUnlock()
c, err := tx.cursor(name)
if err != nil {
return 0, false, err
} else if c == nil {
if err == ErrBitmapNotFound {
return 0, false, nil
} else if err != nil {
return 0, false, err
} else if err := c.First(); err == io.EOF {
return 0, false, nil
} else if err != nil {
@ -1192,10 +1188,10 @@ func (tx *Tx) CountRange(name string, start, end uint64) (uint64, error) {
ekey := highbits(end)
csr, err := tx.cursor(name)
if err != nil {
return 0, err
} else if csr == nil {
if err == ErrBitmapNotFound {
return 0, nil
} else if err != nil {
return 0, err
}
exact, err := csr.Seek(skey)
@ -1262,7 +1258,9 @@ func (tx *Tx) OffsetRange(name string, offset, start, endx uint64) (*roaring.Bit
defer tx.mu.Unlock()
c, err := tx.cursor(name)
if err != nil {
if err == ErrBitmapNotFound {
return roaring.NewSliceBitmap(), nil
} else if err != nil {
return nil, err
}
@ -1270,11 +1268,6 @@ func (tx *Tx) OffsetRange(name string, offset, start, endx uint64) (*roaring.Bit
off := highbits(offset)
hi0, hi1 := highbits(start), highbits(endx)
if c == nil {
// bitmap not found. Match what roaring does and return nil in this case.
return other, nil
}
if _, err := c.Seek(hi0); err == io.EOF {
return other, nil
} else if err != nil {
@ -1302,7 +1295,7 @@ func (tx *Tx) OffsetRange(name string, offset, start, endx uint64) (*roaring.Bit
// containerIterator wraps Cursor to implement roaring.ContainerIterator.
type containerIterator struct {
cursor *Cursor
cursor Cursor
}
// Close is a no-op. It exists to implement the roaring.ContainerIterator interface.
@ -1496,7 +1489,7 @@ func (tx *Tx) ImportRoaringBits(name string, itr roaring.RoaringIterator, clear
changed += nsynth
rowSet[currRow] += nsynth
if err := tx.putContainerWithCursor(cur, itrKey, synthC); err != nil {
if err := tx.putContainerWithCursor(&cur, itrKey, synthC); err != nil {
return changed, rowSet, err
}
continue
@ -1517,7 +1510,7 @@ func (tx *Tx) ImportRoaringBits(name string, itr roaring.RoaringIterator, clear
changes := int(existN - newC.N())
changed += changes
rowSet[currRow] -= changes
err = tx.putContainerWithCursor(cur, itrKey, newC)
err = tx.putContainerWithCursor(&cur, itrKey, newC)
if err != nil {
return
}
@ -1535,7 +1528,7 @@ func (tx *Tx) ImportRoaringBits(name string, itr roaring.RoaringIterator, clear
// can nsynth be zero? No, because of the continue/invariant above where nsynth > 0
changed += nsynth
rowSet[currRow] += nsynth
err = tx.putContainerWithCursor(cur, itrKey, synthC)
err = tx.putContainerWithCursor(&cur, itrKey, synthC)
if err != nil {
return
}
@ -1552,7 +1545,7 @@ func (tx *Tx) ImportRoaringBits(name string, itr roaring.RoaringIterator, clear
changed += changes
rowSet[currRow] += changes
err = tx.putContainerWithCursor(cur, itrKey, newC)
err = tx.putContainerWithCursor(&cur, itrKey, newC)
if err != nil {
panicOn(err)
return

View file

@ -362,13 +362,13 @@ func TestTx_CursorCrashArray(t *testing.T) {
if err != nil {
t.Fatal(err)
}
//setArray(t, 0, 2379, c)
//setArray(t, 1, 2337, c)
setArray(t, 32, 1216, c)
setArray(t, 33, 1195, c)
setArray(t, 48, 1186, c)
setArray(t, 49, 1223, c)
setArray(t, 50, 1223, c)
//setArray(t, 0, 2379, &c)
//setArray(t, 1, 2337, &c)
setArray(t, 32, 1216, &c)
setArray(t, 33, 1195, &c)
setArray(t, 48, 1186, &c)
setArray(t, 49, 1223, &c)
setArray(t, 50, 1223, &c)
}
@ -388,8 +388,8 @@ func TestTx_CursorCrashBitmap(t *testing.T) {
if err != nil {
t.Fatal(err)
}
setArray(t, 0, 22510, c)
setArray(t, 1, 23584, c)
setArray(t, 0, 22510, &c)
setArray(t, 1, 23584, &c)
}
func setArray(tb testing.TB, key, num int, c *rbf.Cursor) {