@@ -275,23 +275,15 @@ func (s *store) restore() error {
275
275
}
276
276
277
277
// index keys concurrently as they're loaded in from tx
278
- unorderedc , donec := make (chan map [string ]* keyIndex ), make (chan struct {})
279
- go func () {
280
- defer close (donec )
281
- for unordered := range unorderedc {
282
- // restore the tree index from the unordered index.
283
- for _ , v := range unordered {
284
- s .kvindex .Insert (v )
285
- }
286
- }
287
- }()
278
+ rkvc , revc := restoreIntoIndex (s .kvindex )
288
279
for {
289
280
keys , vals := tx .UnsafeRange (keyBucketName , min , max , int64 (restoreChunkKeys ))
290
281
if len (keys ) == 0 {
291
282
break
292
283
}
293
- // unbuffered so keys don't pile up in memory
294
- unorderedc <- s .restoreChunk (keys , vals , keyToLease )
284
+ // rkvc blocks if the total pending keys exceeds the restore
285
+ // chunk size to keep keys from consuming too much memory.
286
+ restoreChunk (rkvc , keys , vals , keyToLease )
295
287
if len (keys ) < restoreChunkKeys {
296
288
// partial set implies final set
297
289
break
@@ -301,8 +293,8 @@ func (s *store) restore() error {
301
293
newMin .sub ++
302
294
revToBytes (newMin , min )
303
295
}
304
- close (unorderedc )
305
- <- donec
296
+ close (rkvc )
297
+ s . currentRev = <- revc
306
298
307
299
// keys in the range [compacted revision -N, compaction] might all be deleted due to compaction.
308
300
// the correct revision should be set to compaction revision in the case, not the largest revision
@@ -334,38 +326,73 @@ func (s *store) restore() error {
334
326
return nil
335
327
}
336
328
337
- func (s * store ) restoreChunk (keys , vals [][]byte , keyToLease map [string ]lease.LeaseID ) map [string ]* keyIndex {
338
- // assume half of keys are overwrites
339
- unordered := make (map [string ]* keyIndex , len (keys )/ 2 )
329
+ type revKeyValue struct {
330
+ key []byte
331
+ kv mvccpb.KeyValue
332
+ kstr string
333
+ }
334
+
335
+ func restoreIntoIndex (idx index ) (chan <- revKeyValue , <- chan int64 ) {
336
+ rkvc , revc := make (chan revKeyValue , restoreChunkKeys ), make (chan int64 , 1 )
337
+ go func () {
338
+ currentRev := int64 (1 )
339
+ defer func () { revc <- currentRev }()
340
+ // restore the tree index from streaming the unordered index.
341
+ kiCache := make (map [string ]* keyIndex , restoreChunkKeys )
342
+ for rkv := range rkvc {
343
+ ki , ok := kiCache [rkv .kstr ]
344
+ // purge cache if too many keys and missing
345
+ if ! ok && len (kiCache ) >= restoreChunkKeys {
346
+ i := 10
347
+ for k := range kiCache {
348
+ delete (kiCache , k )
349
+ if i -- ; i == 0 {
350
+ break
351
+ }
352
+ }
353
+ }
354
+ // cache miss, fetch from tree index if there
355
+ if ! ok {
356
+ ki = & keyIndex {key : rkv .kv .Key }
357
+ if idxKey := idx .KeyIndex (ki ); idxKey != nil {
358
+ kiCache [rkv .kstr ], ki = idxKey , idxKey
359
+ ok = true
360
+ }
361
+ }
362
+ rev := bytesToRev (rkv .key )
363
+ currentRev = rev .main
364
+ if ok {
365
+ if isTombstone (rkv .key ) {
366
+ ki .tombstone (rev .main , rev .sub )
367
+ continue
368
+ }
369
+ ki .put (rev .main , rev .sub )
370
+ } else if ! isTombstone (rkv .key ) {
371
+ ki .restore (revision {rkv .kv .CreateRevision , 0 }, rev , rkv .kv .Version )
372
+ idx .Insert (ki )
373
+ kiCache [rkv .kstr ] = ki
374
+ }
375
+ }
376
+ }()
377
+ return rkvc , revc
378
+ }
379
+
380
+ func restoreChunk (kvc chan <- revKeyValue , keys , vals [][]byte , keyToLease map [string ]lease.LeaseID ) {
340
381
for i , key := range keys {
341
- var kv mvccpb. KeyValue
342
- if err := kv .Unmarshal (vals [i ]); err != nil {
382
+ rkv := revKeyValue { key : key }
383
+ if err := rkv . kv .Unmarshal (vals [i ]); err != nil {
343
384
plog .Fatalf ("cannot unmarshal event: %v" , err )
344
385
}
345
- rev := bytesToRev (key [:revBytesLen ])
346
- s .currentRev = rev .main
347
- kstr := string (kv .Key )
386
+ rkv .kstr = string (rkv .kv .Key )
348
387
if isTombstone (key ) {
349
- if ki , ok := unordered [kstr ]; ok {
350
- ki .tombstone (rev .main , rev .sub )
351
- }
352
- delete (keyToLease , kstr )
353
- continue
354
- }
355
- if ki , ok := unordered [kstr ]; ok {
356
- ki .put (rev .main , rev .sub )
357
- } else {
358
- ki = & keyIndex {key : kv .Key }
359
- ki .restore (revision {kv .CreateRevision , 0 }, rev , kv .Version )
360
- unordered [kstr ] = ki
361
- }
362
- if lid := lease .LeaseID (kv .Lease ); lid != lease .NoLease {
363
- keyToLease [kstr ] = lid
388
+ delete (keyToLease , rkv .kstr )
389
+ } else if lid := lease .LeaseID (rkv .kv .Lease ); lid != lease .NoLease {
390
+ keyToLease [rkv .kstr ] = lid
364
391
} else {
365
- delete (keyToLease , kstr )
392
+ delete (keyToLease , rkv . kstr )
366
393
}
394
+ kvc <- rkv
367
395
}
368
- return unordered
369
396
}
370
397
371
398
func (s * store ) Close () error {
0 commit comments