lib/mergeset: skip common prefix in binarySearchKey() function

This should improve performance a bit when the search if performed among items with long common prefix
This commit is contained in:
Aliaksandr Valialkin 2023-07-13 21:53:59 -07:00
parent 3dacdcb707
commit 0c49552849
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1

View file

@ -138,16 +138,7 @@ func (ps *partSearch) Seek(k []byte) {
items := ps.ib.items items := ps.ib.items
data := ps.ib.data data := ps.ib.data
cpLen := commonPrefixLen(ps.ib.commonPrefix, k) cpLen := commonPrefixLen(ps.ib.commonPrefix, k)
if cpLen > 0 { ps.ibItemIdx = binarySearchKey(data, items, k, cpLen)
keySuffix := k[cpLen:]
ps.ibItemIdx = sort.Search(len(items), func(i int) bool {
it := items[i]
it.Start += uint32(cpLen)
return string(keySuffix) <= it.String(data)
})
} else {
ps.ibItemIdx = binarySearchKey(data, items, k)
}
if ps.ibItemIdx < len(items) { if ps.ibItemIdx < len(items) {
// The item has been found. // The item has been found.
return return
@ -165,14 +156,18 @@ func (ps *partSearch) tryFastSeek(k []byte) bool {
if ps.ib == nil { if ps.ib == nil {
return false return false
} }
data := ps.ib.data
items := ps.ib.items items := ps.ib.items
idx := ps.ibItemIdx idx := ps.ibItemIdx
if idx >= len(items) { if idx >= len(items) {
// The ib is exhausted. // The ib is exhausted.
return false return false
} }
if string(k) > items[len(items)-1].String(data) { cpLen := commonPrefixLen(ps.ib.commonPrefix, k)
suffix := k[cpLen:]
it := items[len(items)-1]
it.Start += uint32(cpLen)
data := ps.ib.data
if string(suffix) > it.String(data) {
// The item is located in next blocks. // The item is located in next blocks.
return false return false
} }
@ -181,8 +176,16 @@ func (ps *partSearch) tryFastSeek(k []byte) bool {
if idx > 0 { if idx > 0 {
idx-- idx--
} }
if string(k) < items[idx].String(data) { it = items[idx]
if string(k) < items[0].String(data) { it.Start += uint32(cpLen)
if string(suffix) < it.String(data) {
items = items[:idx]
if len(items) == 0 {
return false
}
it = items[0]
it.Start += uint32(cpLen)
if string(suffix) < it.String(data) {
// The item is located in previous blocks. // The item is located in previous blocks.
return false return false
} }
@ -190,7 +193,7 @@ func (ps *partSearch) tryFastSeek(k []byte) bool {
} }
// The item is located in the current block // The item is located in the current block
ps.ibItemIdx = idx + binarySearchKey(data, items[idx:], k) ps.ibItemIdx = idx + binarySearchKey(data, items[idx:], k, cpLen)
return true return true
} }
@ -330,11 +333,14 @@ func (ps *partSearch) readInmemoryBlock(bh *blockHeader) (*inmemoryBlock, error)
return ib, nil return ib, nil
} }
func binarySearchKey(data []byte, items []Item, key []byte) int { func binarySearchKey(data []byte, items []Item, k []byte, cpLen int) int {
if len(items) == 0 { if len(items) == 0 {
return 0 return 0
} }
if string(key) <= items[0].String(data) { suffix := k[cpLen:]
it := items[0]
it.Start += uint32(cpLen)
if string(suffix) <= it.String(data) {
// Fast path - the item is the first. // Fast path - the item is the first.
return 0 return 0
} }
@ -346,7 +352,9 @@ func binarySearchKey(data []byte, items []Item, key []byte) int {
i, j := uint(0), n i, j := uint(0), n
for i < j { for i < j {
h := uint(i+j) >> 1 h := uint(i+j) >> 1
if h >= 0 && h < uint(len(items)) && string(key) > items[h].String(data) { it := items[h]
it.Start += uint32(cpLen)
if h >= 0 && h < uint(len(items)) && string(suffix) > it.String(data) {
i = h + 1 i = h + 1
} else { } else {
j = h j = h