|
|
|
@ -467,6 +467,20 @@ func (t *freezerTable) truncateHead(items uint64) error { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// sizeHidden returns the total data size of hidden items in the freezer table.
|
|
|
|
|
// This function assumes the lock is already held.
|
|
|
|
|
func (t *freezerTable) sizeHidden() (uint64, error) { |
|
|
|
|
hidden, offset := t.itemHidden.Load(), t.itemOffset.Load() |
|
|
|
|
if hidden <= offset { |
|
|
|
|
return 0, nil |
|
|
|
|
} |
|
|
|
|
indices, err := t.getIndices(hidden-1, 1) |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
return uint64(indices[1].offset), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// truncateTail discards any recent data before the provided threshold number.
|
|
|
|
|
func (t *freezerTable) truncateTail(items uint64) error { |
|
|
|
|
t.lock.Lock() |
|
|
|
@ -495,6 +509,12 @@ func (t *freezerTable) truncateTail(items uint64) error { |
|
|
|
|
newTail.unmarshalBinary(buffer) |
|
|
|
|
newTailId = newTail.filenum |
|
|
|
|
} |
|
|
|
|
// Save the old size for metrics tracking. This needs to be done
|
|
|
|
|
// before any updates to either itemHidden or itemOffset.
|
|
|
|
|
oldSize, err := t.sizeNolock() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
// Update the virtual tail marker and hidden these entries in table.
|
|
|
|
|
t.itemHidden.Store(items) |
|
|
|
|
if err := writeMetadata(t.meta, newMetadata(items)); err != nil { |
|
|
|
@ -509,18 +529,12 @@ func (t *freezerTable) truncateTail(items uint64) error { |
|
|
|
|
if t.tailId > newTailId { |
|
|
|
|
return fmt.Errorf("invalid index, tail-file %d, item-file %d", t.tailId, newTailId) |
|
|
|
|
} |
|
|
|
|
// Hidden items exceed the current tail file, drop the relevant
|
|
|
|
|
// data files. We need to truncate, save the old size for metrics
|
|
|
|
|
// tracking.
|
|
|
|
|
oldSize, err := t.sizeNolock() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
// Count how many items can be deleted from the file.
|
|
|
|
|
var ( |
|
|
|
|
newDeleted = items |
|
|
|
|
deleted = t.itemOffset.Load() |
|
|
|
|
) |
|
|
|
|
// Hidden items exceed the current tail file, drop the relevant data files.
|
|
|
|
|
for current := items - 1; current >= deleted; current -= 1 { |
|
|
|
|
if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil { |
|
|
|
|
return err |
|
|
|
@ -680,6 +694,7 @@ func (t *freezerTable) releaseFilesBefore(num uint32, remove bool) { |
|
|
|
|
func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) { |
|
|
|
|
// Apply the table-offset
|
|
|
|
|
from = from - t.itemOffset.Load() |
|
|
|
|
|
|
|
|
|
// For reading N items, we need N+1 indices.
|
|
|
|
|
buffer := make([]byte, (count+1)*indexEntrySize) |
|
|
|
|
if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil { |
|
|
|
@ -870,14 +885,18 @@ func (t *freezerTable) size() (uint64, error) { |
|
|
|
|
return t.sizeNolock() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// sizeNolock returns the total data size in the freezer table without obtaining
|
|
|
|
|
// the mutex first.
|
|
|
|
|
// sizeNolock returns the total data size in the freezer table. This function
|
|
|
|
|
// assumes the lock is already held.
|
|
|
|
|
func (t *freezerTable) sizeNolock() (uint64, error) { |
|
|
|
|
stat, err := t.index.Stat() |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
total := uint64(t.maxFileSize)*uint64(t.headId-t.tailId) + uint64(t.headBytes) + uint64(stat.Size()) |
|
|
|
|
hidden, err := t.sizeHidden() |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
total := uint64(t.maxFileSize)*uint64(t.headId-t.tailId) + uint64(t.headBytes) + uint64(stat.Size()) - hidden |
|
|
|
|
return total, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|