@@ -269,7 +269,6 @@ notify_deletions([Head|Tail], Penciller) ->
269
269
% % to be merged into multiple SSTs at a lower level.
270
270
% %
271
271
% % SrcLevel is the level of the src sst file, the sink should be srcLevel + 1
272
-
273
272
perform_merge (Manifest , Src , SinkList , SrcLevel , RootPath , NewSQN , OptsSST ) ->
274
273
leveled_log :log (pc010 , [leveled_pmanifest :entry_filename (Src ), NewSQN ]),
275
274
SrcList = [{next , Src , all }],
@@ -279,72 +278,188 @@ perform_merge(Manifest, Src, SinkList, SrcLevel, RootPath, NewSQN, OptsSST) ->
279
278
),
280
279
SinkLevel = SrcLevel + 1 ,
281
280
SinkBasement = leveled_pmanifest :is_basement (Manifest , SinkLevel ),
282
- Additions =
281
+ MaxMergeBelow = OptsSST # sst_options .max_mergebelow ,
282
+ MergeLimit = merge_limit (SrcLevel , length (SinkList ), MaxMergeBelow ),
283
+ {L2Additions , L1Additions , L2FileRemainder } =
283
284
do_merge (
284
285
SrcList , SinkList ,
285
286
SinkLevel , SinkBasement ,
286
287
RootPath , NewSQN , MaxSQN ,
287
288
OptsSST ,
288
- []
289
+ [],
290
+ MergeLimit
291
+ ),
292
+ RevertPointerFun = fun ({next , ME , _SK }) -> ME end ,
293
+ SinkManifestRemovals =
294
+ lists :subtract (
295
+ lists :map (RevertPointerFun , SinkList ),
296
+ lists :map (RevertPointerFun , L2FileRemainder )
289
297
),
290
- RevertPointerFun =
291
- fun ({next , ME , _SK }) ->
292
- ME
293
- end ,
294
- SinkManifestList = lists :map (RevertPointerFun , SinkList ),
295
298
Man0 =
296
299
leveled_pmanifest :replace_manifest_entry (
297
300
Manifest ,
298
301
NewSQN ,
299
302
SinkLevel ,
300
- SinkManifestList ,
301
- Additions
303
+ SinkManifestRemovals ,
304
+ L2Additions
302
305
),
303
- Man2 =
304
- leveled_pmanifest :remove_manifest_entry (
305
- Man0 ,
306
- NewSQN ,
307
- SrcLevel ,
308
- Src
306
+ Man1 =
307
+ case L1Additions of
308
+ [] ->
309
+ leveled_pmanifest :remove_manifest_entry (
310
+ Man0 ,
311
+ NewSQN ,
312
+ SrcLevel ,
313
+ Src
314
+ );
315
+ PartialFiles ->
316
+ leveled_pmanifest :replace_manifest_entry (
317
+ Man0 ,
318
+ NewSQN ,
319
+ SrcLevel ,
320
+ [Src ],
321
+ PartialFiles
322
+ )
323
+ end ,
324
+ {Man1 , [Src |SinkManifestRemovals ]}.
325
+
326
+ -spec merge_limit (
327
+ non_neg_integer (), non_neg_integer (), pos_integer ()|infinity )
328
+ -> pos_integer ()|infinity .
329
+ merge_limit (SrcLevel , SinkListLength , MMB ) when SrcLevel =< 1 ; SinkListLength < MMB ->
330
+ infinity ;
331
+ merge_limit (SrcLevel , SinkListLength , MMB ) when is_integer (MMB ) ->
332
+ AdditionsLimit = max (1 , MMB div 2 ),
333
+ leveled_log :log (pc026 , [SrcLevel + 1 , SinkListLength , AdditionsLimit ]),
334
+ AdditionsLimit .
335
+
336
+ -type merge_maybe_expanded_pointer () ::
337
+ leveled_codec :ledger_kv ()|
338
+ leveled_sst :slot_pointer ()|
339
+ leveled_sst :sst_pointer ().
340
+ % Different to leveled_sst:maybe_expanded_pointer/0
341
+ % No sst_closed_pointer()
342
+
343
+ -spec do_merge (
344
+ list (merge_maybe_expanded_pointer ()),
345
+ list (merge_maybe_expanded_pointer ()),
346
+ leveled_pmanifest :lsm_level (),
347
+ boolean (),
348
+ string (),
349
+ pos_integer (),
350
+ pos_integer (),
351
+ leveled_sst :sst_options (),
352
+ list (leveled_pmanifest :manifest_entry ()),
353
+ pos_integer ()|infinity ) ->
354
+ {
355
+ list (leveled_pmanifest :manifest_entry ()),
356
+ list (leveled_pmanifest :manifest_entry ()),
357
+ list (leveled_sst :sst_pointer ())
358
+ }.
359
+ do_merge (
360
+ [], [], SinkLevel , _SinkB , _RP , NewSQN , _MaxSQN , _Opts , Additions , _Max ) ->
361
+ leveled_log :log (pc011 , [NewSQN , SinkLevel , length (Additions ), full ]),
362
+ {lists :reverse (Additions ), [], []};
363
+ do_merge (
364
+ KL1 , KL2 , SinkLevel , SinkB , RP , NewSQN , MaxSQN , OptsSST , Additions , Max )
365
+ when length (Additions ) >= Max ->
366
+ leveled_log :log (pc011 , [NewSQN , SinkLevel , length (Additions ), partial ]),
367
+ FNSrc =
368
+ leveled_penciller :sst_filename (
369
+ NewSQN , SinkLevel - 1 , 1
309
370
),
310
- {Man2 , [Src |SinkManifestList ]}.
311
-
312
- do_merge ([], [], SinkLevel , _SinkB , _RP , NewSQN , _MaxSQN , _Opts , Additions ) ->
313
- leveled_log :log (pc011 , [NewSQN , SinkLevel , length (Additions )]),
314
- lists :reverse (Additions );
315
- do_merge (KL1 , KL2 , SinkLevel , SinkB , RP , NewSQN , MaxSQN , OptsSST , Additions ) ->
371
+ FNSnk =
372
+ leveled_penciller :sst_filename (
373
+ NewSQN , SinkLevel , length (Additions ) + 1
374
+ ),
375
+ {ExpandedKL1 , []} = split_unexpanded_files (KL1 ),
376
+ {ExpandedKL2 , L2FilePointersRem } = split_unexpanded_files (KL2 ),
377
+ TS1 = os :timestamp (),
378
+ InfOpts = OptsSST # sst_options {max_sstslots = infinity },
379
+ % Need to be careful to make sure all the remainder goes in one file,
380
+ % could be situations whereby the max_sstslots has been changed between
381
+ % restarts - and so there is too much data for one file in the
382
+ % remainder ... but don't want to loop round and consider more complex
383
+ % scenarios here.
384
+ NewMergeKL1 =
385
+ leveled_sst :sst_newmerge (
386
+ RP , FNSrc ,ExpandedKL1 , [], false , SinkLevel - 1 , MaxSQN , InfOpts
387
+ ),
388
+ TS2 = os :timestamp (),
389
+ NewMergeKL2 =
390
+ leveled_sst :sst_newmerge (
391
+ RP , FNSnk , [], ExpandedKL2 , SinkB , SinkLevel , MaxSQN , InfOpts
392
+ ),
393
+ {KL1Additions , [], []} = add_entry (NewMergeKL1 , FNSrc , TS1 , []),
394
+ {KL2Additions , [], []} = add_entry (NewMergeKL2 , FNSnk , TS2 , Additions ),
395
+ {lists :reverse (KL2Additions ), KL1Additions , L2FilePointersRem };
396
+ do_merge (
397
+ KL1 , KL2 , SinkLevel , SinkB , RP , NewSQN , MaxSQN , OptsSST , Additions , Max ) ->
316
398
FileName =
317
399
leveled_penciller :sst_filename (
318
400
NewSQN , SinkLevel , length (Additions )
319
401
),
320
402
leveled_log :log (pc012 , [NewSQN , FileName , SinkB ]),
321
403
TS1 = os :timestamp (),
322
- case leveled_sst :sst_newmerge (RP , FileName ,
323
- KL1 , KL2 , SinkB , SinkLevel , MaxSQN ,
324
- OptsSST ) of
325
- empty ->
326
- leveled_log :log (pc013 , [FileName ]),
327
- do_merge (
328
- [], [],
329
- SinkLevel , SinkB ,
330
- RP , NewSQN , MaxSQN ,
331
- OptsSST ,
332
- Additions
333
- );
334
- {ok , Pid , Reply , Bloom } ->
335
- {{KL1Rem , KL2Rem }, SmallestKey , HighestKey } = Reply ,
336
- Entry =
337
- leveled_pmanifest :new_entry (
338
- SmallestKey , HighestKey , Pid , FileName , Bloom ),
339
- leveled_log :log_timer (pc015 , [], TS1 ),
340
- do_merge (
341
- KL1Rem , KL2Rem ,
342
- SinkLevel , SinkB ,
343
- RP , NewSQN , MaxSQN ,
344
- OptsSST ,
345
- [Entry |Additions ]
346
- )
347
- end .
404
+ NewMerge =
405
+ leveled_sst :sst_newmerge (
406
+ RP , FileName , KL1 , KL2 , SinkB , SinkLevel , MaxSQN , OptsSST ),
407
+ {UpdAdditions , KL1Rem , KL2Rem } =
408
+ add_entry (NewMerge , FileName , TS1 , Additions ),
409
+ do_merge (
410
+ KL1Rem ,
411
+ KL2Rem ,
412
+ SinkLevel ,
413
+ SinkB ,
414
+ RP ,
415
+ NewSQN ,
416
+ MaxSQN ,
417
+ OptsSST ,
418
+ UpdAdditions ,
419
+ Max
420
+ ).
421
+
422
+ add_entry (empty , FileName , _TS1 , Additions ) ->
423
+ leveled_log :log (pc013 , [FileName ]),
424
+ {[], [], Additions };
425
+ add_entry ({ok , Pid , Reply , Bloom }, FileName , TS1 , Additions ) ->
426
+ {{KL1Rem , KL2Rem }, SmallestKey , HighestKey } = Reply ,
427
+ Entry =
428
+ leveled_pmanifest :new_entry (
429
+ SmallestKey , HighestKey , Pid , FileName , Bloom ),
430
+ leveled_log :log_timer (pc015 , [], TS1 ),
431
+ {[Entry |Additions ], KL1Rem , KL2Rem }.
432
+
433
+
434
+ -spec split_unexpanded_files (
435
+ list (merge_maybe_expanded_pointer ())) ->
436
+ {
437
+ list (leveled_codec :ledger_kv ()|leveled_sst :slot_pointer ()),
438
+ list (leveled_sst :sst_pointer ())
439
+ }.
440
+ split_unexpanded_files (Pointers ) ->
441
+ split_unexpanded_files (Pointers , [], []).
442
+
443
+ -spec split_unexpanded_files (
444
+ list (merge_maybe_expanded_pointer ()),
445
+ list (leveled_codec :ledger_kv ()|leveled_sst :slot_pointer ()),
446
+ list (leveled_sst :sst_pointer ())) ->
447
+ {
448
+ list (leveled_codec :ledger_kv ()|leveled_sst :slot_pointer ()),
449
+ list (leveled_sst :sst_pointer ())
450
+ }.
451
+ split_unexpanded_files ([], MaybeExpanded , FilePointers ) ->
452
+ {lists :reverse (MaybeExpanded ), lists :reverse (FilePointers )};
453
+ split_unexpanded_files ([{next , P , SK }|Rest ], MaybeExpanded , FilePointers ) ->
454
+ split_unexpanded_files (Rest , MaybeExpanded , [{next , P , SK }|FilePointers ]);
455
+ split_unexpanded_files ([{LK , LV }|Rest ], MaybeExpanded , []) ->
456
+ % Should never see this, once a FilePointer has been seen
457
+ split_unexpanded_files (Rest , [{LK , LV }|MaybeExpanded ], []);
458
+ split_unexpanded_files ([{pointer , P , SIV , SK , EK }|Rest ], MaybeExpanded , []) ->
459
+ % Should never see this, once a FilePointer has been seen
460
+ split_unexpanded_files (
461
+ Rest , [{pointer , P , SIV , SK , EK }|MaybeExpanded ], []
462
+ ).
348
463
349
464
-spec grooming_scorer (
350
465
list (leveled_pmanifest :manifest_entry ()))
0 commit comments