diff --git a/lib/mergeset/encoding.go b/lib/mergeset/encoding.go index a347084fa..94eaa1415 100644 --- a/lib/mergeset/encoding.go +++ b/lib/mergeset/encoding.go @@ -11,10 +11,20 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" ) +type byteSliceSorter [][]byte + +func (s byteSliceSorter) Len() int { return len(s) } +func (s byteSliceSorter) Less(i, j int) bool { + return string(s[i]) < string(s[j]) +} +func (s byteSliceSorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + type inmemoryBlock struct { commonPrefix []byte data []byte - items [][]byte + items byteSliceSorter } func (ib *inmemoryBlock) Reset() { @@ -77,12 +87,9 @@ func (ib *inmemoryBlock) Add(x []byte) bool { // It must fit CPU cache size, i.e. 64KB for the current CPUs. const maxInmemoryBlockSize = 64 * 1024 -func (ib *inmemoryBlock) itemsLess(i, j int) bool { - return string(ib.items[i]) < string(ib.items[j]) -} - func (ib *inmemoryBlock) sort() { - sort.Slice(ib.items, ib.itemsLess) + // Use sort.Sort instead of sort.Slice in order to eliminate memory allocation. + sort.Sort(&ib.items) bb := bbPool.Get() b := bytesutil.Resize(bb.B, len(ib.data)) b = b[:0] @@ -120,7 +127,8 @@ func checkMarshalType(mt marshalType) error { } func (ib *inmemoryBlock) isSorted() bool { - return sort.SliceIsSorted(ib.items, ib.itemsLess) + // Use sort.IsSorted instead of sort.SliceIsSorted in order to eliminate memory allocation. + return sort.IsSorted(&ib.items) } // MarshalUnsortedData marshals unsorted items from ib to sb. @@ -138,6 +146,8 @@ func (ib *inmemoryBlock) MarshalUnsortedData(sb *storageBlock, firstItemDst, com return ib.marshalData(sb, firstItemDst, commonPrefixDst, compressLevel) } +var isInTest bool + // MarshalUnsortedData marshals sorted items from ib to sb. // // It also: @@ -146,9 +156,9 @@ func (ib *inmemoryBlock) MarshalUnsortedData(sb *storageBlock, firstItemDst, com // - returns the number of items encoded including the first item. // - returns the marshal type used for the encoding. func (ib *inmemoryBlock) MarshalSortedData(sb *storageBlock, firstItemDst, commonPrefixDst []byte, compressLevel int) ([]byte, []byte, uint32, marshalType) { - // if !ib.isSorted() { - // logger.Panicf("BUG: %d items must be sorted; items:\n%s", len(ib.items), ib.debugItemsString()) - // } + if isInTest && !ib.isSorted() { + logger.Panicf("BUG: %d items must be sorted; items:\n%s", len(ib.items), ib.debugItemsString()) + } ib.updateCommonPrefix() return ib.marshalData(sb, firstItemDst, commonPrefixDst, compressLevel) } diff --git a/lib/mergeset/table_search_test.go b/lib/mergeset/table_search_test.go index cfb721bb9..806e2a887 100644 --- a/lib/mergeset/table_search_test.go +++ b/lib/mergeset/table_search_test.go @@ -11,6 +11,7 @@ import ( ) func TestMain(m *testing.M) { + isInTest = true n := m.Run() os.Exit(n) }