From c587dbc94dcef89dd68d4c6b8e70ebf9d0cb7df8 Mon Sep 17 00:00:00 2001 From: Seebs Date: Mon, 13 May 2019 12:36:03 -0500 Subject: [PATCH] drop enterprise/b We added the containers_btree implementation to roaring/, which makes it silly to keep this one. Also, this one is the only reason that container.Mapped needed to be exported. --- enterprise/b/btree.go | 953 ------------------------------- enterprise/b/containers_btree.go | 212 ------- enterprise/enterprise.go | 10 - 3 files changed, 1175 deletions(-) delete mode 100644 enterprise/b/btree.go delete mode 100644 enterprise/b/containers_btree.go diff --git a/enterprise/b/btree.go b/enterprise/b/btree.go deleted file mode 100644 index 2fa5c24e8..000000000 --- a/enterprise/b/btree.go +++ /dev/null @@ -1,953 +0,0 @@ -// This file is a modified redistribution of b (https://github.com/cznic/b), -// which is governed by the following license notice: -// -// Copyright (c) 2014 The b Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the names of the authors nor the names of the -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package b - -import ( - "io" - "sync" - - "github.com/pilosa/pilosa/roaring" -) - -const ( - // kx must be >= 2 - kx = 128 //TODO benchmark tune this number if using custom key/value type(s). - // kd must be >= 1 - kd = 128 //TODO benchmark tune this number if using custom key/value type(s). -) - -var ( - btDPool = sync.Pool{New: func() interface{} { return &d{} }} - btEPool = btEpool{sync.Pool{New: func() interface{} { return &enumerator{} }}} - btTPool = btTpool{sync.Pool{New: func() interface{} { return &tree{} }}} - btXPool = sync.Pool{New: func() interface{} { return &x{} }} -) - -type btTpool struct{ sync.Pool } - -func (p *btTpool) get(cmp Cmp) *tree { - x := p.Get().(*tree) - x.cmp = cmp - return x -} - -type btEpool struct{ sync.Pool } - -func (p *btEpool) get(err error, hit bool, i int, k uint64, q *d, t *tree, ver int64) *enumerator { - x := p.Get().(*enumerator) - x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver - return x -} - -type ( - // Cmp compares a and b. Return value is: - // - // < 0 if a < b - // 0 if a == b - // > 0 if a > b - // - Cmp func(a, b uint64) int64 - - d struct { // data page - c int - d [2*kd + 1]de - n *d - p *d - } - - de struct { // d element - k uint64 - v *roaring.Container - } - - // enumerator captures the state of enumerating a tree. It is returned - // from the Seek* methods. The enumerator is aware of any mutations - // made to the tree in the process of enumerating it and automatically - // resumes the enumeration at the proper key, if possible. - // - // However, once an enumerator returns io.EOF to signal "no more - // items", it does no more attempt to "resync" on tree mutation(s). In - // other words, io.EOF from an enumerator is "sticky" (idempotent). - enumerator struct { - err error - hit bool - i int - k uint64 - q *d - t *tree - ver int64 - } - - // tree is a B+tree. - tree struct { - c int - cmp Cmp - first *d - last *d - r interface{} - ver int64 - } - - xe struct { // x element - ch interface{} - k uint64 - } - - x struct { // index page - c int - x [2*kx + 2]xe - } -) - -var ( // R/O zero values - zd d - zde de - ze enumerator - zk uint64 - zt tree - zx x - zxe xe -) - -func clr(q interface{}) { - switch x := q.(type) { - case *x: - for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn - clr(x.x[i].ch) - } - *x = zx - btXPool.Put(x) - case *d: - *x = zd - btDPool.Put(x) - } -} - -// -------------------------------------------------------------------------- x - -func newX(ch0 interface{}) *x { - r := btXPool.Get().(*x) - r.x[0].ch = ch0 - return r -} - -func (q *x) extract(i int) { - q.c-- - if i < q.c { - copy(q.x[i:], q.x[i+1:q.c+1]) - q.x[q.c].ch = q.x[q.c+1].ch - q.x[q.c].k = zk // GC - q.x[q.c+1] = zxe // GC - } -} - -func (q *x) insert(i int, k uint64, ch interface{}) *x { - c := q.c - if i < c { - q.x[c+1].ch = q.x[c].ch - copy(q.x[i+2:], q.x[i+1:c]) - q.x[i+1].k = q.x[i].k - } - c++ - q.c = c - q.x[i].k = k - q.x[i+1].ch = ch - return q -} - -func (q *x) siblings(i int) (l, r *d) { - if i >= 0 { - if i > 0 { - l = q.x[i-1].ch.(*d) - } - if i < q.c { - r = q.x[i+1].ch.(*d) - } - } - return l, r -} - -// -------------------------------------------------------------------------- d - -func (l *d) mvL(r *d, c int) { - copy(l.d[l.c:], r.d[:c]) - copy(r.d[:], r.d[c:r.c]) - // Zero out the de's here to prevent reading bad data - // and to avoid creating non-collectible (GC) references. - for i := 1; i < c; i++ { - r.d[r.c-i] = zde - } - l.c += c - r.c -= c -} - -func (l *d) mvR(r *d, c int) { - copy(r.d[c:], r.d[:r.c]) - copy(r.d[:c], l.d[l.c-c:]) - // Zero out the de's here to prevent reading bad data - // and to avoid creating non-collectible (GC) references. - for i := 1; i < c; i++ { - l.d[l.c-c+i] = zde - } - r.c += c - l.c -= c -} - -// ----------------------------------------------------------------------- Tree - -// treeNew returns a newly created, empty Tree. The compare function is used -// for key collation. -func treeNew(cmp Cmp) *tree { - return btTPool.get(cmp) -} - -// Clear removes all K/V pairs from the tree. -func (t *tree) Clear() { - if t.r == nil { - return - } - - clr(t.r) - t.c, t.first, t.last, t.r = 0, nil, nil, nil - t.ver++ -} - -// Close performs Clear and recycles t to a pool for possible later reuse. No -// references to t should exist or such references must not be used afterwards. -func (t *tree) Close() { - t.Clear() - *t = zt - btTPool.Put(t) -} - -func (t *tree) cat(p *x, q, r *d, pi int) { - t.ver++ - q.mvL(r, r.c) - if r.n != nil { - r.n.p = q - } else { - t.last = q - } - q.n = r.n - *r = zd - btDPool.Put(r) - if p.c > 1 { - p.extract(pi) - p.x[pi].ch = q - return - } - - switch x := t.r.(type) { - case *x: - *x = zx - btXPool.Put(x) - case *d: - *x = zd - btDPool.Put(x) - } - t.r = q -} - -func (t *tree) catX(p, q, r *x, pi int) { - t.ver++ - q.x[q.c].k = p.x[pi].k - copy(q.x[q.c+1:], r.x[:r.c]) - q.c += r.c + 1 - q.x[q.c].ch = r.x[r.c].ch - *r = zx - btXPool.Put(r) - if p.c > 1 { - p.c-- - pc := p.c - if pi < pc { - p.x[pi].k = p.x[pi+1].k - copy(p.x[pi+1:], p.x[pi+2:pc+1]) - p.x[pc].ch = p.x[pc+1].ch - p.x[pc].k = zk // GC - p.x[pc+1].ch = nil // GC - } - return - } - - switch x := t.r.(type) { - case *x: - *x = zx - btXPool.Put(x) - case *d: - *x = zd - btDPool.Put(x) - } - t.r = q -} - -// Delete removes the k's KV pair, if it exists, in which case Delete returns -// true. -func (t *tree) Delete(k uint64) (ok bool) { - pi := -1 - var p *x - q := t.r - if q == nil { - return false - } - - for { - var i int - i, ok = t.find(q, k) - if ok { - switch x := q.(type) { - case *x: - if x.c < kx && q != t.r { - x, i = t.underflowX(p, x, pi, i) - } - pi = i + 1 - p = x - q = x.x[pi].ch - continue - case *d: - t.extract(x, i) - if x.c >= kd { - return true - } - - if q != t.r { - t.underflow(p, x, pi) - } else if t.c == 0 { - t.Clear() - } - return true - } - } - - switch x := q.(type) { - case *x: - if x.c < kx && q != t.r { - x, i = t.underflowX(p, x, pi, i) - } - pi = i - p = x - q = x.x[i].ch - case *d: - return false - } - } -} - -func (t *tree) extract(q *d, i int) { // (r *container) { - t.ver++ - //r = q.d[i].v // prepared for Extract - q.c-- - if i < q.c { - copy(q.d[i:], q.d[i+1:q.c+1]) - } - q.d[q.c] = zde // GC - t.c-- -} - -func (t *tree) find(q interface{}, k uint64) (i int, ok bool) { - var mk uint64 - l := 0 - switch x := q.(type) { - case *x: - h := x.c - 1 - for l <= h { - m := (l + h) >> 1 - mk = x.x[m].k - switch cmp := t.cmp(k, mk); { - case cmp > 0: - l = m + 1 - case cmp == 0: - return m, true - default: - h = m - 1 - } - } - case *d: - h := x.c - 1 - for l <= h { - m := (l + h) >> 1 - mk = x.d[m].k - switch cmp := t.cmp(k, mk); { - case cmp > 0: - l = m + 1 - case cmp == 0: - return m, true - default: - h = m - 1 - } - } - } - return l, false -} - -// First returns the first item of the tree in the key collating order, or -// (zero-value, zero-value) if the tree is empty. -func (t *tree) First() (k uint64, v *roaring.Container) { - if q := t.first; q != nil { - q := &q.d[0] - k, v = q.k, q.v - } - return k, v -} - -// Get returns the value associated with k and true if it exists. Otherwise Get -// returns (zero-value, false). -func (t *tree) Get(k uint64) (v *roaring.Container, ok bool) { - q := t.r - if q == nil { - return - } - - for { - var i int - if i, ok = t.find(q, k); ok { - switch x := q.(type) { - case *x: - q = x.x[i+1].ch - continue - case *d: - return x.d[i].v, true - } - } - switch x := q.(type) { - case *x: - q = x.x[i].ch - default: - return - } - } -} - -func (t *tree) insert(q *d, i int, k uint64, v *roaring.Container) *d { - t.ver++ - c := q.c - if i < c { - copy(q.d[i+1:], q.d[i:c]) - } - c++ - q.c = c - q.d[i].k, q.d[i].v = k, v - t.c++ - return q -} - -// Last returns the last item of the tree in the key collating order, or -// (zero-value, zero-value) if the tree is empty. -func (t *tree) Last() (k uint64, v *roaring.Container) { - if q := t.last; q != nil { - q := &q.d[q.c-1] - k, v = q.k, q.v - } - return k, v -} - -// Len returns the number of items in the tree. -func (t *tree) Len() int { - return t.c -} - -func (t *tree) overflow(p *x, q *d, pi, i int, k uint64, v *roaring.Container) { - t.ver++ - l, r := p.siblings(pi) - - // s is the number of items to shift out of the full data container to - // allow for the new data item. This logic shifts by half the available - // space plus one. In the case where the new item is to be inserted within - // the calculated shift space, then s is reduced to include only the - // data items up to the index of the new data item. - if l != nil && l.c < 2*kd && i != 0 { - s := (2*kd-l.c)/2 + 1 // half plus one - //s := 2*kd - l.c // all available - if i < s { - s = i - } - l.mvL(q, s) - t.insert(q, i-s, k, v) - p.x[pi-1].k = q.d[0].k - return - } - - if r != nil && r.c < 2*kd { - if i < 2*kd { - s := (2*kd-r.c)/2 + 1 // half plus one - //s := 2*kd - r.c // all available - if 2*kd-i < s { - s = 2*kd - i - } - q.mvR(r, s) - t.insert(q, i, k, v) - p.x[pi].k = r.d[0].k - return - } - - t.insert(r, 0, k, v) - p.x[pi].k = k - return - } - - t.split(p, q, pi, i, k, v) -} - -// Seek returns an Enumerator positioned on an item such that k >= item's key. -// ok reports if k == item.key The Enumerator's position is possibly after the -// last item in the tree. -func (t *tree) Seek(k uint64) (e *enumerator, ok bool) { - q := t.r - if q == nil { - e = btEPool.get(nil, false, 0, k, nil, t, t.ver) - return - } - - for { - var i int - if i, ok = t.find(q, k); ok { - switch x := q.(type) { - case *x: - q = x.x[i+1].ch - continue - case *d: - return btEPool.get(nil, ok, i, k, x, t, t.ver), true - } - } - - switch x := q.(type) { - case *x: - q = x.x[i].ch - case *d: - return btEPool.get(nil, ok, i, k, x, t, t.ver), false - } - } -} - -// SeekFirst returns an enumerator positioned on the first KV pair in the tree, -// if any. For an empty tree, err == io.EOF is returned and e will be nil. -func (t *tree) SeekFirst() (e *enumerator, err error) { - q := t.first - if q == nil { - return nil, io.EOF - } - - return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil -} - -// SeekLast returns an enumerator positioned on the last KV pair in the tree, -// if any. For an empty tree, err == io.EOF is returned and e will be nil. -func (t *tree) SeekLast() (e *enumerator, err error) { - q := t.last - if q == nil { - return nil, io.EOF - } - - return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil -} - -// Set sets the value associated with k. -func (t *tree) Set(k uint64, v *roaring.Container) { - //dbg("--- PRE Set(%v, %v)\n%s", k, v, t.dump()) - //defer func() { - // dbg("--- POST\n%s\n====\n", t.dump()) - //}() - - pi := -1 - var p *x - q := t.r - if q == nil { - z := t.insert(btDPool.Get().(*d), 0, k, v) - t.r, t.first, t.last = z, z, z - return - } - - for { - i, ok := t.find(q, k) - if ok { - switch x := q.(type) { - case *x: - i++ - if x.c > 2*kx { - x, i = t.splitX(p, x, pi, i) - } - pi = i - p = x - q = x.x[i].ch - continue - case *d: - x.d[i].v = v - } - return - } - - switch x := q.(type) { - case *x: - if x.c > 2*kx { - x, i = t.splitX(p, x, pi, i) - } - pi = i - p = x - q = x.x[i].ch - case *d: - switch { - case x.c < 2*kd: - t.insert(x, i, k, v) - default: - t.overflow(p, x, pi, i, k, v) - } - return - } - } -} - -// Put combines Get and Set in a more efficient way where the tree is walked -// only once. The upd(ater) receives (old-value, true) if a KV pair for k -// exists or (zero-value, false) otherwise. It can then return a (new-value, -// true) to create or overwrite the existing value in the KV pair, or -// (whatever, false) if it decides not to create or not to update the value of -// the KV pair. -// -// tree.Set(k, v) call conceptually equals calling -// -// tree.Put(k, func(uint64, bool){ return v, true }) -// -// modulo the differing return values. -func (t *tree) Put(k uint64, upd func(oldV *roaring.Container, exists bool) (newV *roaring.Container, write bool)) (oldV *roaring.Container, written bool) { - pi := -1 - var p *x - q := t.r - var newV *roaring.Container - if q == nil { - // new KV pair in empty tree - newV, written = upd(newV, false) - if !written { - return - } - - z := t.insert(btDPool.Get().(*d), 0, k, newV) - t.r, t.first, t.last = z, z, z - return - } - - for { - i, ok := t.find(q, k) - if ok { - switch x := q.(type) { - case *x: - i++ - if x.c > 2*kx { - x, i = t.splitX(p, x, pi, i) - } - pi = i - p = x - q = x.x[i].ch - continue - case *d: - oldV = x.d[i].v - newV, written = upd(oldV, true) - if !written { - return - } - - x.d[i].v = newV - } - return - } - - switch x := q.(type) { - case *x: - if x.c > 2*kx { - x, i = t.splitX(p, x, pi, i) - } - pi = i - p = x - q = x.x[i].ch - case *d: // new KV pair - newV, written = upd(newV, false) - if !written { - return - } - - switch { - case x.c < 2*kd: - t.insert(x, i, k, newV) - default: - t.overflow(p, x, pi, i, k, newV) - } - return - } - } -} - -func (t *tree) split(p *x, q *d, pi, i int, k uint64, v *roaring.Container) { - t.ver++ - r := btDPool.Get().(*d) - if q.n != nil { - r.n = q.n - r.n.p = r - } else { - t.last = r - } - q.n = r - r.p = q - - copy(r.d[:], q.d[kd:2*kd]) - for i := range q.d[kd:] { - q.d[kd+i] = zde - } - q.c = kd - r.c = kd - var done bool - if i > kd { - done = true - t.insert(r, i-kd, k, v) - } - if pi >= 0 { - p.insert(pi, r.d[0].k, r) - } else { - t.r = newX(q).insert(0, r.d[0].k, r) - } - if done { - return - } - - t.insert(q, i, k, v) -} - -func (t *tree) splitX(p *x, q *x, pi int, i int) (*x, int) { - t.ver++ - r := btXPool.Get().(*x) - copy(r.x[:], q.x[kx+1:]) - q.c = kx - r.c = kx - if pi >= 0 { - p.insert(pi, q.x[kx].k, r) - } else { - t.r = newX(q).insert(0, q.x[kx].k, r) - } - - q.x[kx].k = zk - for i := range q.x[kx+1:] { - q.x[kx+i+1] = zxe - } - if i > kx { - q = r - i -= kx + 1 - } - - return q, i -} - -func (t *tree) underflow(p *x, q *d, pi int) { - t.ver++ - l, r := p.siblings(pi) - - if l != nil && l.c+q.c >= 2*kd { - l.mvR(q, 1) - p.x[pi-1].k = q.d[0].k - return - } - - if r != nil && q.c+r.c >= 2*kd { - q.mvL(r, 1) - p.x[pi].k = r.d[0].k - r.d[r.c] = zde // GC - return - } - - if l != nil { - t.cat(p, l, q, pi-1) - return - } - - t.cat(p, q, r, pi) -} - -func (t *tree) underflowX(p *x, q *x, pi int, i int) (*x, int) { - t.ver++ - var l, r *x - - if pi >= 0 { - if pi > 0 { - l = p.x[pi-1].ch.(*x) - } - if pi < p.c { - r = p.x[pi+1].ch.(*x) - } - } - - if l != nil && l.c > kx { - q.x[q.c+1].ch = q.x[q.c].ch - copy(q.x[1:], q.x[:q.c]) - q.x[0].ch = l.x[l.c].ch - q.x[0].k = p.x[pi-1].k - q.c++ - i++ - l.c-- - p.x[pi-1].k = l.x[l.c].k - return q, i - } - - if r != nil && r.c > kx { - q.x[q.c].k = p.x[pi].k - q.c++ - q.x[q.c].ch = r.x[0].ch - p.x[pi].k = r.x[0].k - copy(r.x[:], r.x[1:r.c]) - r.c-- - rc := r.c - r.x[rc].ch = r.x[rc+1].ch - r.x[rc].k = zk - r.x[rc+1].ch = nil - return q, i - } - - if l != nil { - i += l.c + 1 - t.catX(p, l, q, pi-1) - q = l - return q, i - } - - t.catX(p, q, r, pi) - return q, i -} - -// ----------------------------------------------------------------- Enumerator - -// Close recycles e to a pool for possible later reuse. No references to e -// should exist or such references must not be used afterwards. -func (e *enumerator) Close() { - *e = ze - btEPool.Put(e) -} - -// Next returns the currently enumerated item, if it exists and moves to the -// next item in the key collation order. If there is no item to return, err == -// io.EOF is returned. -func (e *enumerator) Next() (k uint64, v *roaring.Container, err error) { - if err = e.err; err != nil { - return 0, nil, err - } - - if e.ver != e.t.ver { - f, _ := e.t.Seek(e.k) - *e = *f - f.Close() - } - if e.q == nil { - e.err, err = io.EOF, io.EOF - return 0, nil, err - } - - if e.i >= e.q.c { - if err = e.next(); err != nil { - return 0, nil, err - } - } - - i := e.q.d[e.i] - k, v = i.k, i.v - e.k, e.hit = k, true - _ = e.next() - return k, v, nil -} - -func (e *enumerator) next() error { - if e.q == nil { - e.err = io.EOF - return io.EOF - } - - switch { - case e.i < e.q.c-1: - e.i++ - default: - if e.q, e.i = e.q.n, 0; e.q == nil { - e.err = io.EOF - } - } - return e.err -} - -// Prev returns the currently enumerated item, if it exists and moves to the -// previous item in the key collation order. If there is no item to return, err -// == io.EOF is returned. -func (e *enumerator) Prev() (k uint64, v *roaring.Container, err error) { - if err = e.err; err != nil { - return 0, nil, err - } - - if e.ver != e.t.ver { - f, _ := e.t.Seek(e.k) - *e = *f - f.Close() - } - if e.q == nil { - e.err, err = io.EOF, io.EOF - return 0, nil, err - } - - if !e.hit { - // move to previous because Seek overshoots if there's no hit - if err = e.prev(); err != nil { - return 0, nil, err - } - } - - if e.i >= e.q.c { - if err = e.prev(); err != nil { - return 0, nil, err - } - } - - i := e.q.d[e.i] - k, v = i.k, i.v - e.k, e.hit = k, true - _ = e.prev() - return k, v, err -} - -func (e *enumerator) prev() error { - if e.q == nil { - e.err = io.EOF - return io.EOF - } - - switch { - case e.i > 0: - e.i-- - default: - if e.q = e.q.p; e.q == nil { - e.err = io.EOF - break - } - - e.i = e.q.c - 1 - } - return e.err -} diff --git a/enterprise/b/containers_btree.go b/enterprise/b/containers_btree.go deleted file mode 100644 index a051d7cde..000000000 --- a/enterprise/b/containers_btree.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2018 Pilosa Corp. All rights reserved. -// -// This file is part of Pilosa Enterprise Edition. -// -// Pilosa Enterprise Edition is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Pilosa Enterprise Edition is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with Pilosa Enterprise Edition. If not, see . - -package b - -import ( - "io" - - "github.com/pilosa/pilosa/roaring" -) - -func cmp(a, b uint64) int64 { - return int64(a - b) -} - -type bTreeContainers struct { - tree *tree - - lastKey uint64 - lastContainer *roaring.Container -} - -func newBTreeContainers() *bTreeContainers { - return &bTreeContainers{ - tree: treeNew(cmp), - } -} - -func NewBTreeBitmap(a ...uint64) *roaring.Bitmap { - b := &roaring.Bitmap{ - Containers: newBTreeContainers(), - } - // TODO: there's no way to report an error here - _, _ = b.Add(a...) - return b -} - -func (btc *bTreeContainers) Get(key uint64) *roaring.Container { - // Check the last* cache for same container. - if key == btc.lastKey && btc.lastContainer != nil { - return btc.lastContainer - } - - var c *roaring.Container - el, ok := btc.tree.Get(key) - if ok { - c = el - btc.lastKey = key - btc.lastContainer = c - } - return c -} - -func (btc *bTreeContainers) Put(key uint64, c *roaring.Container) { - // If a mapped container is added to the tree, reset the - // lastContainer cache so that the cache is not pointing - // at a read-only mmap. - if c.Mapped() { - btc.lastContainer = nil - } - btc.tree.Set(key, c) -} - -func (u updater) update(oldV *roaring.Container, exists bool) (*roaring.Container, bool) { - // update the existing container - if exists { - oldV.Update(u.containerType, u.n, u.mapped) - return oldV, false - } - cont := roaring.NewContainer() - cont.Update(u.containerType, u.n, u.mapped) - return cont, true -} - -// this struct is added to prevent the closure locals from being escaped out to the heap -type updater struct { - key uint64 - n int32 - containerType byte - mapped bool -} - -func (btc *bTreeContainers) PutContainerValues(key uint64, typ byte, n int, mapped bool) { - a := updater{key, int32(n), typ, mapped} - btc.tree.Put(key, a.update) -} - -func (btc *bTreeContainers) Remove(key uint64) { - btc.tree.Delete(key) -} - -func (btc *bTreeContainers) GetOrCreate(key uint64) *roaring.Container { - // Check the last* cache for same container. - if key == btc.lastKey && btc.lastContainer != nil { - return btc.lastContainer - } - - btc.lastKey = key - v, ok := btc.tree.Get(key) - if !ok { - cont := roaring.NewContainerArray(nil) - btc.tree.Set(key, cont) - btc.lastContainer = cont - return cont - } - - btc.lastContainer = v - return btc.lastContainer -} - -func (btc *bTreeContainers) Count() (n uint64) { - e, _ := btc.tree.Seek(0) - _, c, err := e.Next() - for err != io.EOF { - n += uint64(c.N()) - _, c, err = e.Next() - } - return n -} - -func (btc *bTreeContainers) Clone() roaring.Containers { - nbtc := newBTreeContainers() - - itr, err := btc.tree.SeekFirst() - if err == io.EOF { - return nbtc - } - for { - k, v, err := itr.Next() - if err == io.EOF { - break - } - nbtc.tree.Set(k, v.Clone()) - } - return nbtc -} - -func (btc *bTreeContainers) Last() (key uint64, c *roaring.Container) { - if btc.tree.Len() == 0 { - return 0, nil - } - k, v := btc.tree.Last() - return k, v -} - -func (btc *bTreeContainers) Size() int { - return btc.tree.Len() -} - -func (btc *bTreeContainers) Reset() { - btc.tree = treeNew(cmp) - btc.lastKey = 0 - btc.lastContainer = nil -} - -func (btc *bTreeContainers) Iterator(key uint64) (citer roaring.ContainerIterator, found bool) { - e, ok := btc.tree.Seek(key) - if ok { - found = true - } - - return &btcIterator{ - e: e, - }, found -} - -func (btc *bTreeContainers) Repair() { - e, _ := btc.tree.Seek(0) - _, c, err := e.Next() - for err != io.EOF { - c.Repair() - _, c, err = e.Next() - } -} - -type btcIterator struct { - e *enumerator - key uint64 - val *roaring.Container -} - -func (i *btcIterator) Next() bool { - - k, v, err := i.e.Next() - if err == io.EOF { - return false - } - i.key = k - i.val = v - return true -} - -func (i *btcIterator) Value() (uint64, *roaring.Container) { - if i.val == nil { - return 0, nil - } - return i.key, i.val -} diff --git a/enterprise/enterprise.go b/enterprise/enterprise.go index a75223801..f3a897551 100644 --- a/enterprise/enterprise.go +++ b/enterprise/enterprise.go @@ -21,13 +21,3 @@ // "ENTERPRISE=1 make install". These features were dual-licensed separately // from Pilosa community edition under the AGPL and Pilosa's commercial license. package enterprise - -import ( - "github.com/pilosa/pilosa/enterprise/b" - "github.com/pilosa/pilosa/roaring" -) - -func init() { // nolint: gochecknoinits - // Replace Bitmap constructor with B+Tree implementation - roaring.NewFileBitmap = b.NewBTreeBitmap -}