From 619bc1bcd9501157d22c913d71a1d13786a26d25 Mon Sep 17 00:00:00 2001 From: Travis Turner Date: Tue, 25 Sep 2018 14:57:12 -0500 Subject: [PATCH] implements fragment.setRow(row, rowID) --- fragment.go | 54 +++++++++++++++++++++++++++++++++++++-- fragment_internal_test.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/fragment.go b/fragment.go index ee586afc6..63c9cce37 100644 --- a/fragment.go +++ b/fragment.go @@ -352,11 +352,11 @@ func (f *fragment) unprotectedRow(rowID uint64) *Row { } // Only use a subset of the containers. - // NOTE: The start & end ranges must be divisible by + // NOTE: The start & end ranges must be divisible by container width. data := f.storage.OffsetRange(f.shard*ShardWidth, rowID*ShardWidth, (rowID+1)*ShardWidth) // Reference bitmap subrange in storage. - // We Clone() data because otherwise row will contains pointers to containers in storage. + // We Clone() data because otherwise row will contain pointers to containers in storage. // This causes unexpected results when we cache the row and try to use it later. row := &Row{ segments: []rowSegment{{ @@ -491,6 +491,56 @@ func (f *fragment) unprotectedClearBit(rowID, columnID uint64) (changed bool, er return changed, nil } +// setRow replaces an existing row (specified by rowID) with the given +// Row. This updates both the on-disk storage and the in-cache bitmap. +func (f *fragment) setRow(row *Row, rowID uint64) (bool, error) { + f.mu.Lock() + defer f.mu.Unlock() + return f.unprotectedSetRow(row, rowID) +} + +func (f *fragment) unprotectedSetRow(row *Row, rowID uint64) (changed bool, err error) { + // TODO: In order to return `changed`, we need to first compare + // the existing row with the given row. Determine if the overhead + // of this is worth having `changed`. + // For now we will assume changed is always true. + changed = true + + // First container of the row in storage. + headContainerKey := rowID << shardVsContainerExponent + + // Remove every existing container in the row. + for i := uint64(0); i < (1 << shardVsContainerExponent); i++ { + f.storage.Containers.Remove(headContainerKey + i) + } + + // From the given row, get the rowSegment for this shard. + seg := row.segment(f.shard) + if seg == nil { + return changed, nil + } + + // Put each container from rowSegment to fragment storage. + citer, _ := seg.data.Containers.Iterator(f.shard << shardVsContainerExponent) + for citer.Next() { + k, c := citer.Value() + f.storage.Containers.Put(headContainerKey+(k%(1<