55 "sync"
66 "sync/atomic"
77 "time"
8+
9+ "github.com/emirpasic/gods/trees/btree"
810)
911
1012// Internal cache errors
@@ -31,8 +33,8 @@ type AtomicCache struct {
3133 // Deadlock mutex for debugging purpose.
3234 // deadlock.RWMutex
3335
34- // Lookup structure used for global index. It is based on hashtable structure.
35- lookup map [ string ] LookupRecord
36+ // Lookup structure used for global index. It is based on BTree structure.
37+ lookup * btree. Tree
3638
3739 // Shards lookup tables which contains information about shards sections.
3840 smallShards , mediumShards , largeShards ShardsLookup
@@ -86,7 +88,7 @@ type LookupRecord struct {
8688}
8789
8890// BufferItem is used for buffer, which contains all unattended cache set
89- // requrest .
91+ // request .
9092type BufferItem struct {
9193 Key []byte
9294 Data []byte
@@ -103,7 +105,7 @@ func New(opts ...Option) *AtomicCache {
103105 MaxShardsSmall : 256 ,
104106 MaxShardsMedium : 128 ,
105107 MaxShardsLarge : 64 ,
106- GcStarter : 5000 ,
108+ GcStarter : 25000 ,
107109 }
108110
109111 for _ , opt := range opts {
@@ -114,7 +116,7 @@ func New(opts ...Option) *AtomicCache {
114116 cache := & AtomicCache {}
115117
116118 // Init lookup table
117- cache .lookup = make ( map [ string ] LookupRecord )
119+ cache .lookup = btree . NewWithStringComparator ( 3 )
118120
119121 // Init small shards section
120122 initShardsSection (& cache .smallShards , options .MaxShardsSmall , options .MaxRecords , options .RecordSizeSmall )
@@ -163,15 +165,15 @@ func (a *AtomicCache) Set(key []byte, data []byte, expire time.Duration) error {
163165 shardSection , shardSectionID := a .getShardsSectionBySize (len (data ))
164166
165167 a .Lock ()
166- if ival , ok := a .lookup [ string (key )] ; ! ok {
168+ if ival , ok := a .lookup . Get ( string (key )) ; ! ok {
167169 new = true
168170 } else {
169- val := ival
171+ val := ival .( LookupRecord )
170172
171173 if val .ShardSection != shardSectionID {
172174 shardSection .shards [val .ShardIndex ].Free (val .RecordIndex )
173175 val .RecordIndex = shardSection .shards [val .ShardIndex ].Set (data )
174- a .lookup [ string (key )] = LookupRecord {ShardIndex : val .ShardIndex , ShardSection : shardSectionID , RecordIndex : val .RecordIndex , Expiration : a .getExprTime (expire )}
176+ a .lookup . Put ( string (key ), LookupRecord {ShardIndex : val .ShardIndex , ShardSection : shardSectionID , RecordIndex : val .RecordIndex , Expiration : a .getExprTime (expire )})
175177 } else {
176178 prevShardSection := a .getShardsSectionByID (val .ShardSection )
177179 prevShardSection .shards [val .ShardIndex ].Free (val .RecordIndex )
@@ -182,11 +184,11 @@ func (a *AtomicCache) Set(key []byte, data []byte, expire time.Duration) error {
182184 if new {
183185 if si , ok := a .getShard (shardSectionID ); ok {
184186 ri := shardSection .shards [si ].Set (data )
185- a .lookup [ string (key )] = LookupRecord {ShardIndex : si , ShardSection : shardSectionID , RecordIndex : ri , Expiration : a .getExprTime (expire )}
187+ a .lookup . Put ( string (key ), LookupRecord {ShardIndex : si , ShardSection : shardSectionID , RecordIndex : ri , Expiration : a .getExprTime (expire )})
186188 } else if si , ok := a .getEmptyShard (shardSectionID ); ok {
187189 shardSection .shards [si ] = NewShard (a .MaxRecords , a .getRecordSizeByShardSectionID (shardSectionID ))
188190 ri := shardSection .shards [si ].Set (data )
189- a .lookup [ string (key )] = LookupRecord {ShardIndex : si , ShardSection : shardSectionID , RecordIndex : ri , Expiration : a .getExprTime (expire )}
191+ a .lookup . Put ( string (key ), LookupRecord {ShardIndex : si , ShardSection : shardSectionID , RecordIndex : ri , Expiration : a .getExprTime (expire )})
190192 } else {
191193 if len (a .buffer ) <= int (a .MaxRecords ) {
192194 a .buffer = append (a .buffer , BufferItem {Key : key , Data : data , Expire : expire })
@@ -215,7 +217,8 @@ func (a *AtomicCache) Get(key []byte) ([]byte, error) {
215217 var hit = false
216218
217219 a .RLock ()
218- if val , ok := a .lookup [string (key )]; ok {
220+ if ival , ok := a .lookup .Get (string (key )); ok {
221+ val := ival .(LookupRecord )
219222 shardSection := a .getShardsSectionByID (val .ShardSection )
220223
221224 if shardSection .shards [val .ShardIndex ] != nil && time .Now ().Before (val .Expiration ) {
@@ -355,14 +358,16 @@ func (a *AtomicCache) getExprTime(expire time.Duration) time.Time {
355358// active shard).
356359func (a * AtomicCache ) collectGarbage () {
357360 a .Lock ()
358- for k , v := range a .lookup {
361+ for _ , k := range a .lookup .Keys () {
362+ iv , _ := a .lookup .Get (k .(string )) // get record
363+ v := iv .(LookupRecord ) // convert record from interface to LookupRecord
359364 shardSection := a .getShardsSectionByID (v .ShardSection ) // get shard section
360365 if time .Now ().After (v .Expiration ) {
361366 shardSection .shards [v .ShardIndex ].Free (v .RecordIndex )
362367 if len (shardSection .shardsActive ) > 1 {
363368 a .releaseShard (v .ShardSection , v .ShardIndex )
364369 }
365- delete ( a .lookup , k )
370+ a .lookup . Remove ( k )
366371 }
367372 }
368373
0 commit comments