diff --git a/fragment.go b/fragment.go index c6cc03291..728fe9dee 100644 --- a/fragment.go +++ b/fragment.go @@ -118,8 +118,6 @@ type fragment struct { // Stats reporting. maxRowID uint64 - minRowID uint64 - hasRowID bool // Cache containing full rows (not just counts). rowCache bitmapCache @@ -191,9 +189,6 @@ func (f *fragment) Open() error { // Read last bit to determine max row. f.maxRowID = f.storage.Max() / ShardWidth - min, ok := f.storage.Min() - f.minRowID = min / ShardWidth - f.hasRowID = ok f.stats.Gauge("rows", float64(f.maxRowID), 1.0) return nil }(); err != nil { @@ -525,10 +520,6 @@ func (f *fragment) unprotectedSetBit(rowID, columnID uint64) (changed bool, err f.maxRowID = rowID f.stats.Gauge("rows", float64(f.maxRowID), 1.0) } - if !f.hasRowID || rowID < f.minRowID { - f.minRowID = rowID - f.hasRowID = true - } return changed, nil } @@ -1040,12 +1031,13 @@ func (f *fragment) maxUnsigned(filter *Row, bitDepth uint) (max int64, count uin // if filter is nil, it returns fragment.minRowID, 1 // if fragment has no rows, it returns 0, 0 func (f *fragment) minRow(filter *Row) (uint64, uint64) { - if f.hasRowID { + minRowID, hasRowID := f.minRowID() + if hasRowID { if filter == nil { - return f.minRowID, 1 + return minRowID, 1 } // iterate from min row ID and return the first that intersects with filter. - for i := f.minRowID; i <= f.maxRowID; i++ { + for i := minRowID; i <= f.maxRowID; i++ { row := f.row(i).Intersect(filter) count := row.Count() if count > 0 { @@ -1060,12 +1052,14 @@ func (f *fragment) minRow(filter *Row) (uint64, uint64) { // if filter is nil, it returns fragment.maxRowID, 1 // if fragment has no rows, it returns 0, 0 func (f *fragment) maxRow(filter *Row) (uint64, uint64) { - if f.hasRowID { + minRowID, hasRowID := f.minRowID() + if hasRowID { if filter == nil { return f.maxRowID, 1 } // iterate back from max row ID and return the first that intersects with filter. - for i := f.maxRowID; i >= f.minRowID; i-- { + // TODO: implement reverse container iteration to improve performance here for sparse data. --Jaffee + for i := f.maxRowID; i >= minRowID; i-- { row := f.row(i).Intersect(filter) count := row.Count() if count > 0 { @@ -2419,6 +2413,11 @@ func (f *fragment) readCacheFromArchive(r io.Reader) error { return nil } +func (f *fragment) minRowID() (uint64, bool) { + min, ok := f.storage.Min() + return min / ShardWidth, ok +} + // rowFilter is a function signature for controlling iteration over containers // in a fragment. It will be invoked on each container found and returns two // booleans. The first is whether the row this container is in should be diff --git a/roaring/roaring.go b/roaring/roaring.go index 7addfc2f4..f7c3feb37 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -2008,12 +2008,12 @@ func (c *Container) arrayMax() uint16 { func (c *Container) bitmapMax() uint16 { // Search bitmap in reverse order. bitmap := c.bitmap() - for i := len(bitmap) - 1; i > 0; i-- { + for i := len(bitmap); i > 0; i-- { // If value is zero then skip. - v := bitmap[i] + v := bitmap[i-1] if v != 0 { r := bits.LeadingZeros64(v) - return uint16(i*64 + 63 - r) + return uint16((i-1)*64 + 63 - r) } } return 0