mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-06-28 15:41:13 +08:00
Further improve memory usage of needle_map.CompactMap()
. (#6825)
This commit is contained in:
parent
283d9e0079
commit
9ffc8bcb54
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
batch = 10000
|
MaxSectionBucketSize = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
type SectionalNeedleId uint32
|
type SectionalNeedleId uint32
|
||||||
@ -28,15 +28,14 @@ type CompactSection struct {
|
|||||||
overflow Overflow
|
overflow Overflow
|
||||||
start NeedleId
|
start NeedleId
|
||||||
end NeedleId
|
end NeedleId
|
||||||
counter int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Overflow []SectionalNeedleValue
|
type Overflow []SectionalNeedleValue
|
||||||
|
|
||||||
func NewCompactSection(start NeedleId) *CompactSection {
|
func NewCompactSection(start NeedleId) *CompactSection {
|
||||||
return &CompactSection{
|
return &CompactSection{
|
||||||
values: []SectionalNeedleValue{},
|
values: make([]SectionalNeedleValue, 0),
|
||||||
overflow: Overflow([]SectionalNeedleValue{}),
|
overflow: Overflow(make([]SectionalNeedleValue, 0)),
|
||||||
start: start,
|
start: start,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,9 +56,13 @@ func (cs *CompactSection) Set(key NeedleId, offset Offset, size Size) (oldOffset
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needOverflow := cs.counter >= batch
|
var lkey SectionalNeedleId
|
||||||
needOverflow = needOverflow || cs.counter > 0 && cs.values[cs.counter-1].Key > skey
|
if len(cs.values) > 0 {
|
||||||
if !needOverflow {
|
lkey = cs.values[len(cs.values)-1].Key
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(cs.values) < MaxSectionBucketSize && lkey <= skey:
|
||||||
// non-overflow insert
|
// non-overflow insert
|
||||||
cs.values = append(cs.values, SectionalNeedleValue{
|
cs.values = append(cs.values, SectionalNeedleValue{
|
||||||
Key: skey,
|
Key: skey,
|
||||||
@ -67,17 +70,13 @@ func (cs *CompactSection) Set(key NeedleId, offset Offset, size Size) (oldOffset
|
|||||||
Size: size,
|
Size: size,
|
||||||
OffsetHigher: offset.OffsetHigher,
|
OffsetHigher: offset.OffsetHigher,
|
||||||
})
|
})
|
||||||
cs.counter++
|
case len(cs.values) < MaxSectionBucketSize:
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lookBackIndex := cs.counter - 128
|
|
||||||
if lookBackIndex < 0 {
|
|
||||||
lookBackIndex = 0
|
|
||||||
}
|
|
||||||
if cs.counter < batch && cs.values[lookBackIndex].Key < skey {
|
|
||||||
// still has capacity and only partially out of order
|
// still has capacity and only partially out of order
|
||||||
for ; lookBackIndex < cs.counter; lookBackIndex++ {
|
lookBackIndex := len(cs.values) - 128
|
||||||
|
if lookBackIndex < 0 {
|
||||||
|
lookBackIndex = 0
|
||||||
|
}
|
||||||
|
for ; lookBackIndex < len(cs.values); lookBackIndex++ {
|
||||||
if cs.values[lookBackIndex].Key >= skey {
|
if cs.values[lookBackIndex].Key >= skey {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -86,17 +85,21 @@ func (cs *CompactSection) Set(key NeedleId, offset Offset, size Size) (oldOffset
|
|||||||
copy(cs.values[lookBackIndex+1:], cs.values[lookBackIndex:])
|
copy(cs.values[lookBackIndex+1:], cs.values[lookBackIndex:])
|
||||||
cs.values[lookBackIndex].Key, cs.values[lookBackIndex].Size = skey, size
|
cs.values[lookBackIndex].Key, cs.values[lookBackIndex].Size = skey, size
|
||||||
cs.values[lookBackIndex].OffsetLower, cs.values[lookBackIndex].OffsetHigher = offset.OffsetLower, offset.OffsetHigher
|
cs.values[lookBackIndex].OffsetLower, cs.values[lookBackIndex].OffsetHigher = offset.OffsetLower, offset.OffsetHigher
|
||||||
cs.counter++
|
default:
|
||||||
|
// overflow insert
|
||||||
|
if oldValue, found := cs.findOverflowEntry(skey); found {
|
||||||
|
oldOffset.OffsetHigher, oldOffset.OffsetLower, oldSize = oldValue.OffsetHigher, oldValue.OffsetLower, oldValue.Size
|
||||||
|
}
|
||||||
|
cs.setOverflowEntry(skey, offset, size)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow insert
|
// if we maxed out our values bucket, pin its capacity to minimize memory usage
|
||||||
//println("start", cs.start, "counter", cs.counter, "key", key)
|
if len(cs.values) == MaxSectionBucketSize {
|
||||||
if oldValue, found := cs.findOverflowEntry(skey); found {
|
bucket := make([]SectionalNeedleValue, len(cs.values))
|
||||||
oldOffset.OffsetHigher, oldOffset.OffsetLower, oldSize = oldValue.OffsetHigher, oldValue.OffsetLower, oldValue.Size
|
copy(bucket, cs.values)
|
||||||
|
cs.values = bucket
|
||||||
}
|
}
|
||||||
cs.setOverflowEntry(skey, offset, size)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,10 +180,10 @@ func (cs *CompactSection) Get(key NeedleId) (*NeedleValue, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
func (cs *CompactSection) binarySearchValues(key SectionalNeedleId) int {
|
func (cs *CompactSection) binarySearchValues(key SectionalNeedleId) int {
|
||||||
x := sort.Search(cs.counter, func(i int) bool {
|
x := sort.Search(len(cs.values), func(i int) bool {
|
||||||
return cs.values[i].Key >= key
|
return cs.values[i].Key >= key
|
||||||
})
|
})
|
||||||
if x == cs.counter {
|
if x >= len(cs.values) {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
if cs.values[x].Key > key {
|
if cs.values[x].Key > key {
|
||||||
@ -242,7 +245,7 @@ func (cm *CompactMap) binarySearchCompactSection(key NeedleId) int {
|
|||||||
return -5
|
return -5
|
||||||
}
|
}
|
||||||
if cm.list[h].start <= key {
|
if cm.list[h].start <= key {
|
||||||
if cm.list[h].counter < batch || key <= cm.list[h].end {
|
if len(cm.list[h].values) < MaxSectionBucketSize || key <= cm.list[h].end {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
return -4
|
return -4
|
||||||
@ -267,7 +270,7 @@ func (cm *CompactMap) AscendingVisit(visit func(NeedleValue) error) error {
|
|||||||
for _, cs := range cm.list {
|
for _, cs := range cm.list {
|
||||||
cs.RLock()
|
cs.RLock()
|
||||||
var i, j int
|
var i, j int
|
||||||
for i, j = 0, 0; i < len(cs.overflow) && j < len(cs.values) && j < cs.counter; {
|
for i, j = 0, 0; i < len(cs.overflow) && j < len(cs.values); {
|
||||||
if cs.overflow[i].Key < cs.values[j].Key {
|
if cs.overflow[i].Key < cs.values[j].Key {
|
||||||
if err := visit(toNeedleValue(cs.overflow[i], cs)); err != nil {
|
if err := visit(toNeedleValue(cs.overflow[i], cs)); err != nil {
|
||||||
cs.RUnlock()
|
cs.RUnlock()
|
||||||
@ -290,7 +293,7 @@ func (cm *CompactMap) AscendingVisit(visit func(NeedleValue) error) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ; j < len(cs.values) && j < cs.counter; j++ {
|
for ; j < len(cs.values); j++ {
|
||||||
if err := visit(toNeedleValue(cs.values[j], cs)); err != nil {
|
if err := visit(toNeedleValue(cs.values[j], cs)); err != nil {
|
||||||
cs.RUnlock()
|
cs.RUnlock()
|
||||||
return err
|
return err
|
||||||
|
@ -2,11 +2,12 @@ package needle_map
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/seaweedfs/seaweedfs/weed/sequence"
|
|
||||||
. "github.com/seaweedfs/seaweedfs/weed/storage/types"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/seaweedfs/seaweedfs/weed/sequence"
|
||||||
|
. "github.com/seaweedfs/seaweedfs/weed/storage/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSnowflakeSequencer(t *testing.T) {
|
func TestSnowflakeSequencer(t *testing.T) {
|
||||||
@ -65,15 +66,15 @@ func TestIssue52(t *testing.T) {
|
|||||||
|
|
||||||
func TestCompactMap(t *testing.T) {
|
func TestCompactMap(t *testing.T) {
|
||||||
m := NewCompactMap()
|
m := NewCompactMap()
|
||||||
for i := uint32(0); i < 100*batch; i += 2 {
|
for i := uint32(0); i < 100*MaxSectionBucketSize; i += 2 {
|
||||||
m.Set(NeedleId(i), ToOffset(int64(i)), Size(i))
|
m.Set(NeedleId(i), ToOffset(int64(i)), Size(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uint32(0); i < 100*batch; i += 37 {
|
for i := uint32(0); i < 100*MaxSectionBucketSize; i += 37 {
|
||||||
m.Delete(NeedleId(i))
|
m.Delete(NeedleId(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uint32(0); i < 10*batch; i += 3 {
|
for i := uint32(0); i < 10*MaxSectionBucketSize; i += 3 {
|
||||||
m.Set(NeedleId(i), ToOffset(int64(i+11)), Size(i+5))
|
m.Set(NeedleId(i), ToOffset(int64(i+11)), Size(i+5))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ func TestCompactMap(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
for i := uint32(0); i < 10*batch; i++ {
|
for i := uint32(0); i < 10*MaxSectionBucketSize; i++ {
|
||||||
v, ok := m.Get(NeedleId(i))
|
v, ok := m.Get(NeedleId(i))
|
||||||
if i%3 == 0 {
|
if i%3 == 0 {
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -103,7 +104,7 @@ func TestCompactMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := uint32(10 * batch); i < 100*batch; i++ {
|
for i := uint32(10 * MaxSectionBucketSize); i < 100*MaxSectionBucketSize; i++ {
|
||||||
v, ok := m.Get(NeedleId(i))
|
v, ok := m.Get(NeedleId(i))
|
||||||
if i%37 == 0 {
|
if i%37 == 0 {
|
||||||
if ok && v.Size.IsValid() {
|
if ok && v.Size.IsValid() {
|
||||||
|
Loading…
Reference in New Issue
Block a user