refactored bunchCache; add more tests
parent
64b2689ab8
commit
94b5999756
|
@ -192,6 +192,44 @@ func TestWriteDiffBunch(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestMergeIdRefs(t *testing.T) {
|
||||
bunch := []IdRef{}
|
||||
|
||||
bunch = mergeBunch(bunch, []IdRef{IdRef{50, []int64{1}}})
|
||||
if b := bunch[0]; b.id != 50 || b.refs[0] != 1 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
|
||||
// before
|
||||
bunch = mergeBunch(bunch, []IdRef{IdRef{40, []int64{3}}})
|
||||
if b := bunch[0]; b.id != 40 || b.refs[0] != 3 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
|
||||
// after
|
||||
bunch = mergeBunch(bunch, []IdRef{IdRef{70, []int64{4}}})
|
||||
if b := bunch[2]; b.id != 70 || b.refs[0] != 4 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
|
||||
// in between
|
||||
bunch = mergeBunch(bunch, []IdRef{IdRef{60, []int64{5}}})
|
||||
if b := bunch[2]; b.id != 60 || b.refs[0] != 5 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
|
||||
// same
|
||||
bunch = mergeBunch(bunch, []IdRef{IdRef{50, []int64{0, 5}}})
|
||||
if b := bunch[1]; b.id != 50 || b.refs[0] != 0 ||
|
||||
b.refs[1] != 1 || b.refs[2] != 5 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
|
||||
if len(bunch) != 4 {
|
||||
t.Fatal(bunch)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIdRefBunches(t *testing.T) {
|
||||
bunches := make(IdRefBunches)
|
||||
bunches.add(1, 100, 999)
|
||||
|
@ -200,12 +238,6 @@ func TestIdRefBunches(t *testing.T) {
|
|||
t.Fatal(bunches)
|
||||
}
|
||||
|
||||
// same id
|
||||
bunches.add(1, 100, 998)
|
||||
if r := bunches[1].idRefs[0]; r.id != 100 || r.refs[0] != 998 || r.refs[1] != 999 {
|
||||
t.Fatal(bunches)
|
||||
}
|
||||
|
||||
// before
|
||||
bunches.add(1, 99, 888)
|
||||
if r := bunches[1].idRefs[0]; r.id != 99 || r.refs[0] != 888 {
|
||||
|
@ -224,6 +256,12 @@ func TestIdRefBunches(t *testing.T) {
|
|||
t.Fatal(bunches)
|
||||
}
|
||||
|
||||
// same id
|
||||
bunches.add(1, 100, 998)
|
||||
if r := bunches[1].idRefs[1]; r.id != 100 || r.refs[0] != 998 || r.refs[1] != 999 {
|
||||
t.Fatal(bunches)
|
||||
}
|
||||
|
||||
if len(bunches) != 1 {
|
||||
t.Fatal(bunches)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,55 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
type IdRef struct {
|
||||
id int64
|
||||
refs []int64
|
||||
}
|
||||
|
||||
// IdRefBunch stores multiple IdRefs
|
||||
type IdRefBunch struct {
|
||||
id int64 // the bunch id
|
||||
idRefs []IdRef
|
||||
}
|
||||
|
||||
// IdRefBunches can hold multiple IdRefBunch
|
||||
type IdRefBunches map[int64]IdRefBunch
|
||||
|
||||
func (bunches *IdRefBunches) add(bunchId, id, ref int64) {
|
||||
bunch, ok := (*bunches)[bunchId]
|
||||
if !ok {
|
||||
bunch = IdRefBunch{id: bunchId}
|
||||
}
|
||||
var idRef *IdRef
|
||||
|
||||
i := sort.Search(len(bunch.idRefs), func(i int) bool {
|
||||
return bunch.idRefs[i].id >= id
|
||||
})
|
||||
if i < len(bunch.idRefs) && bunch.idRefs[i].id >= id {
|
||||
if bunch.idRefs[i].id == id {
|
||||
idRef = &bunch.idRefs[i]
|
||||
} else {
|
||||
bunch.idRefs = append(bunch.idRefs, IdRef{})
|
||||
copy(bunch.idRefs[i+1:], bunch.idRefs[i:])
|
||||
bunch.idRefs[i] = IdRef{id: id}
|
||||
idRef = &bunch.idRefs[i]
|
||||
}
|
||||
} else {
|
||||
bunch.idRefs = append(bunch.idRefs, IdRef{id: id})
|
||||
idRef = &bunch.idRefs[len(bunch.idRefs)-1]
|
||||
}
|
||||
|
||||
idRef.refs = insertRefs(idRef.refs, ref)
|
||||
(*bunches)[bunchId] = bunch
|
||||
}
|
||||
|
||||
var IdRefBunchesPool chan IdRefBunches
|
||||
|
||||
func init() {
|
||||
IdRefBunchesPool = make(chan IdRefBunches, 1)
|
||||
}
|
||||
|
||||
// BunchRefCache
|
||||
type BunchRefCache struct {
|
||||
Cache
|
||||
cache IdRefBunches
|
||||
|
@ -21,24 +70,6 @@ type BunchRefCache struct {
|
|||
waitWrite *sync.WaitGroup
|
||||
}
|
||||
|
||||
var IdRefBunchesCache chan IdRefBunches
|
||||
|
||||
func init() {
|
||||
IdRefBunchesCache = make(chan IdRefBunches, 1)
|
||||
}
|
||||
|
||||
type IdRef struct {
|
||||
id int64
|
||||
refs []int64
|
||||
}
|
||||
|
||||
type IdRefBunch struct {
|
||||
id int64
|
||||
idRefs []IdRef
|
||||
}
|
||||
|
||||
type IdRefBunches map[int64]IdRefBunch
|
||||
|
||||
func NewBunchRefCache(path string, opts *CacheOptions) (*BunchRefCache, error) {
|
||||
index := BunchRefCache{}
|
||||
index.options = opts
|
||||
|
@ -83,7 +114,7 @@ func (index *BunchRefCache) dispatch() {
|
|||
if len(index.cache) >= cacheSize {
|
||||
index.write <- index.cache
|
||||
select {
|
||||
case index.cache = <-IdRefBunchesCache:
|
||||
case index.cache = <-IdRefBunchesPool:
|
||||
default:
|
||||
index.cache = make(IdRefBunches, cacheSize)
|
||||
}
|
||||
|
@ -106,34 +137,6 @@ func (index *BunchRefCache) getBunchId(id int64) int64 {
|
|||
return id / 64
|
||||
}
|
||||
|
||||
func (bunches *IdRefBunches) add(bunchId, id, ref int64) {
|
||||
bunch, ok := (*bunches)[bunchId]
|
||||
if !ok {
|
||||
bunch = IdRefBunch{id: bunchId}
|
||||
}
|
||||
var idRef *IdRef
|
||||
|
||||
i := sort.Search(len(bunch.idRefs), func(i int) bool {
|
||||
return bunch.idRefs[i].id >= id
|
||||
})
|
||||
if i < len(bunch.idRefs) && bunch.idRefs[i].id >= id {
|
||||
if bunch.idRefs[i].id == id {
|
||||
idRef = &bunch.idRefs[i]
|
||||
} else {
|
||||
bunch.idRefs = append(bunch.idRefs, IdRef{})
|
||||
copy(bunch.idRefs[i+1:], bunch.idRefs[i:])
|
||||
bunch.idRefs[i] = IdRef{id: id}
|
||||
idRef = &bunch.idRefs[i]
|
||||
}
|
||||
} else {
|
||||
bunch.idRefs = append(bunch.idRefs, IdRef{id: id})
|
||||
idRef = &bunch.idRefs[len(bunch.idRefs)-1]
|
||||
}
|
||||
|
||||
idRef.refs = insertRefs(idRef.refs, ref)
|
||||
(*bunches)[bunchId] = bunch
|
||||
}
|
||||
|
||||
type loadBunchItem struct {
|
||||
bunchId int64
|
||||
bunch IdRefBunch
|
||||
|
@ -184,12 +187,44 @@ func (index *BunchRefCache) writeRefs(idRefs IdRefBunches) error {
|
|||
delete(idRefs, k)
|
||||
}
|
||||
select {
|
||||
case IdRefBunchesCache <- idRefs:
|
||||
case IdRefBunchesPool <- idRefs:
|
||||
}
|
||||
}()
|
||||
return index.db.Write(index.wo, batch)
|
||||
|
||||
}
|
||||
|
||||
func mergeBunch(bunch, newBunch []IdRef) []IdRef {
|
||||
lastIdx := 0
|
||||
|
||||
NextIdRef:
|
||||
// for each new IdRef...
|
||||
for _, newIdRefs := range newBunch {
|
||||
// search place in bunch
|
||||
for i := lastIdx; i < len(bunch); i++ {
|
||||
if bunch[i].id == newIdRefs.id {
|
||||
// id already present, add refs
|
||||
for _, r := range newIdRefs.refs {
|
||||
bunch[i].refs = insertRefs(bunch[i].refs, r)
|
||||
}
|
||||
lastIdx = i
|
||||
break NextIdRef
|
||||
}
|
||||
if bunch[i].id > newIdRefs.id {
|
||||
// insert before
|
||||
bunch = append(bunch, IdRef{})
|
||||
copy(bunch[i+1:], bunch[i:])
|
||||
bunch[i] = newIdRefs
|
||||
lastIdx = i
|
||||
break NextIdRef
|
||||
}
|
||||
}
|
||||
// insert at the end
|
||||
bunch = append(bunch, newIdRefs)
|
||||
lastIdx = len(bunch) - 1
|
||||
}
|
||||
return bunch
|
||||
}
|
||||
|
||||
func (index *BunchRefCache) loadMergeMarshal(keyBuf []byte, newBunch []IdRef) []byte {
|
||||
data, err := index.db.Get(index.ro, keyBuf)
|
||||
if err != nil {
|
||||
|
@ -205,26 +240,7 @@ func (index *BunchRefCache) loadMergeMarshal(keyBuf []byte, newBunch []IdRef) []
|
|||
if bunch == nil {
|
||||
bunch = newBunch
|
||||
} else {
|
||||
var last int
|
||||
for _, newIdRefs := range newBunch {
|
||||
for i := last; i < len(bunch); i++ {
|
||||
if bunch[i].id == newIdRefs.id {
|
||||
for _, r := range newIdRefs.refs {
|
||||
bunch[i].refs = insertRefs(bunch[i].refs, r)
|
||||
}
|
||||
last = i
|
||||
break
|
||||
}
|
||||
if bunch[i].id >= newIdRefs.id {
|
||||
// insert before
|
||||
bunch = append(bunch, IdRef{})
|
||||
copy(bunch[i+1:], bunch[i:])
|
||||
bunch[i] = newIdRefs
|
||||
last = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
bunch = mergeBunch(bunch, newBunch)
|
||||
}
|
||||
|
||||
data = MarshalBunch(bunch)
|
||||
|
|
Loading…
Reference in New Issue