@@ -384,11 +384,22 @@ mocha.describe('md_store', function() {
384384 frag_size : 10 ,
385385 dedup_key : Buffer . from ( 'noobaa' )
386386 } ;
387+ const block = {
388+ _id : md_store . make_md_id ( ) ,
389+ system : system_id ,
390+ bucket : bucket . _id ,
391+ node : md_store . make_md_id ( ) ,
392+ chunk : chunk . _id ,
393+ frag : chunk . frags [ 0 ] . _id ,
394+ size : 10 ,
395+ } ;
387396 await md_store . insert_chunks ( [ chunk ] ) ;
397+ await md_store . insert_blocks ( [ block ] ) ;
388398 const chunksArr = await md_store . find_chunks_by_dedup_key ( bucket , [ Buffer . from ( 'noobaa' ) . toString ( 'base64' ) ] ) ;
389399 assert ( Array . isArray ( chunksArr ) ) ;
390400 assert ( chunksArr . length >= 1 ) ;
391401 assert ( chunksArr [ 0 ] . frags [ 0 ] ?. _id ?. toString ( ) === chunk . frags [ 0 ] . _id . toString ( ) ) ;
402+ assert ( chunksArr [ 0 ] . frags [ 0 ] . blocks . length >= 1 ) ;
392403 } ) ;
393404
394405 mocha . it ( 'test find_chunks_by_dedup_key - dedup_key doesnt exist in DB' , async ( ) => {
@@ -408,6 +419,94 @@ mocha.describe('md_store', function() {
408419 assert ( chunksArr . length === 0 ) ;
409420 } ) ;
410421
422+ mocha . it ( 'find_chunks_by_dedup_key - multiple chunks with multiple frags and blocks' , async ( ) => {
423+ if ( config . DB_TYPE !== 'postgres' ) return ;
424+ const bucket = { _id : md_store . make_md_id ( ) , system : { _id : system_id } } ;
425+ const frag1a = { _id : md_store . make_md_id ( ) } ;
426+ const frag1b = { _id : md_store . make_md_id ( ) } ;
427+ const frag2a = { _id : md_store . make_md_id ( ) } ;
428+ const chunk1 = {
429+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
430+ frags : [ frag1a , frag1b ] , size : 10 , frag_size : 5 ,
431+ dedup_key : Buffer . from ( 'multi_test_key1' ) ,
432+ } ;
433+ const chunk2 = {
434+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
435+ frags : [ frag2a ] , size : 20 , frag_size : 20 ,
436+ dedup_key : Buffer . from ( 'multi_test_key2' ) ,
437+ } ;
438+ const blocks = [
439+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
440+ node : md_store . make_md_id ( ) , chunk : chunk1 . _id , frag : frag1a . _id , size : 5 } ,
441+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
442+ node : md_store . make_md_id ( ) , chunk : chunk1 . _id , frag : frag1a . _id , size : 5 } ,
443+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
444+ node : md_store . make_md_id ( ) , chunk : chunk1 . _id , frag : frag1b . _id , size : 5 } ,
445+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
446+ node : md_store . make_md_id ( ) , chunk : chunk2 . _id , frag : frag2a . _id , size : 20 } ,
447+ ] ;
448+ await md_store . insert_chunks ( [ chunk1 , chunk2 ] ) ;
449+ await md_store . insert_blocks ( blocks ) ;
450+
451+ const dedup_keys = [
452+ Buffer . from ( 'multi_test_key1' ) . toString ( 'base64' ) ,
453+ Buffer . from ( 'multi_test_key2' ) . toString ( 'base64' ) ,
454+ ] ;
455+ const result = await md_store . find_chunks_by_dedup_key ( bucket , dedup_keys ) ;
456+
457+ assert ( result . length === 2 ) ;
458+ const res_chunk1 = result . find ( c => c . _id . toString ( ) === chunk1 . _id . toString ( ) ) ;
459+ const res_chunk2 = result . find ( c => c . _id . toString ( ) === chunk2 . _id . toString ( ) ) ;
460+ assert ( res_chunk1 ) ;
461+ assert ( res_chunk2 ) ;
462+ assert ( res_chunk1 . frags [ 0 ] . blocks . length === 2 ) ;
463+ assert ( res_chunk1 . frags [ 1 ] . blocks . length === 1 ) ;
464+ assert ( res_chunk2 . frags [ 0 ] . blocks . length === 1 ) ;
465+ } ) ;
466+
467+ mocha . it ( 'find_chunks_by_dedup_key - excludes deleted chunks' , async ( ) => {
468+ if ( config . DB_TYPE !== 'postgres' ) return ;
469+ const bucket = { _id : md_store . make_md_id ( ) , system : { _id : system_id } } ;
470+ const chunk = {
471+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
472+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
473+ dedup_key : Buffer . from ( 'deleted_chunk_key' ) ,
474+ } ;
475+ const block = {
476+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
477+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 10 ,
478+ } ;
479+ await md_store . insert_chunks ( [ chunk ] ) ;
480+ await md_store . insert_blocks ( [ block ] ) ;
481+ await md_store . delete_chunks_by_ids ( [ chunk . _id ] ) ;
482+
483+ const dk = Buffer . from ( 'deleted_chunk_key' ) . toString ( 'base64' ) ;
484+ const result = await md_store . find_chunks_by_dedup_key ( bucket , [ dk ] ) ;
485+ assert ( result . length === 0 ) ;
486+ } ) ;
487+
488+ mocha . it ( 'find_chunks_by_dedup_key - excludes deleted blocks' , async ( ) => {
489+ if ( config . DB_TYPE !== 'postgres' ) return ;
490+ const bucket = { _id : md_store . make_md_id ( ) , system : { _id : system_id } } ;
491+ const chunk = {
492+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
493+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
494+ dedup_key : Buffer . from ( 'deleted_block_key' ) ,
495+ } ;
496+ const block = {
497+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bucket . _id ,
498+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 10 ,
499+ } ;
500+ await md_store . insert_chunks ( [ chunk ] ) ;
501+ await md_store . insert_blocks ( [ block ] ) ;
502+ await md_store . delete_blocks_by_ids ( [ block . _id ] ) ;
503+
504+ const dk = Buffer . from ( 'deleted_block_key' ) . toString ( 'base64' ) ;
505+ const result = await md_store . find_chunks_by_dedup_key ( bucket , [ dk ] ) ;
506+ // chunk has no non-deleted blocks, so INNER JOIN excludes it
507+ assert ( result . length === 0 ) ;
508+ } ) ;
509+
411510 } ) ;
412511
413512
@@ -433,6 +532,134 @@ mocha.describe('md_store', function() {
433532
434533 } ) ;
435534
535+ mocha . describe ( 'load_blocks_for_chunks' , function ( ) {
536+
537+ mocha . it ( 'loads blocks and groups them into chunk.frags[].blocks' , async function ( ) {
538+ if ( config . DB_TYPE !== 'postgres' ) return ;
539+ const bid = md_store . make_md_id ( ) ;
540+ const frag1 = { _id : md_store . make_md_id ( ) } ;
541+ const frag2 = { _id : md_store . make_md_id ( ) } ;
542+ const chunk = {
543+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
544+ frags : [ frag1 , frag2 ] , size : 10 , frag_size : 5 ,
545+ } ;
546+ const blocks = [
547+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
548+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : frag1 . _id , size : 5 } ,
549+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
550+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : frag1 . _id , size : 5 } ,
551+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
552+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : frag2 . _id , size : 5 } ,
553+ ] ;
554+ await md_store . insert_chunks ( [ chunk ] ) ;
555+ await md_store . insert_blocks ( blocks ) ;
556+
557+ await md_store . load_blocks_for_chunks ( [ chunk ] ) ;
558+
559+ assert ( chunk . frags [ 0 ] . blocks . length === 2 ) ;
560+ assert ( chunk . frags [ 1 ] . blocks . length === 1 ) ;
561+ assert ( chunk . frags [ 1 ] . blocks [ 0 ] . _id . toString ( ) === blocks [ 2 ] . _id . toString ( ) ) ;
562+ } ) ;
563+
564+ mocha . it ( 'handles multiple chunks at once' , async function ( ) {
565+ if ( config . DB_TYPE !== 'postgres' ) return ;
566+ const bid = md_store . make_md_id ( ) ;
567+ const chunk1 = {
568+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
569+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
570+ } ;
571+ const chunk2 = {
572+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
573+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 20 , frag_size : 20 ,
574+ } ;
575+ const blocks = [
576+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
577+ node : md_store . make_md_id ( ) , chunk : chunk1 . _id , frag : chunk1 . frags [ 0 ] . _id , size : 10 } ,
578+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
579+ node : md_store . make_md_id ( ) , chunk : chunk2 . _id , frag : chunk2 . frags [ 0 ] . _id , size : 20 } ,
580+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
581+ node : md_store . make_md_id ( ) , chunk : chunk2 . _id , frag : chunk2 . frags [ 0 ] . _id , size : 20 } ,
582+ ] ;
583+ await md_store . insert_chunks ( [ chunk1 , chunk2 ] ) ;
584+ await md_store . insert_blocks ( blocks ) ;
585+
586+ await md_store . load_blocks_for_chunks ( [ chunk1 , chunk2 ] ) ;
587+
588+ assert ( chunk1 . frags [ 0 ] . blocks . length === 1 ) ;
589+ assert ( chunk2 . frags [ 0 ] . blocks . length === 2 ) ;
590+ } ) ;
591+
592+ mocha . it ( 'sets empty blocks array for chunks with no blocks' , async function ( ) {
593+ if ( config . DB_TYPE !== 'postgres' ) return ;
594+ const chunk = {
595+ _id : md_store . make_md_id ( ) , system : system_id , bucket : md_store . make_md_id ( ) ,
596+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
597+ } ;
598+ await md_store . insert_chunks ( [ chunk ] ) ;
599+
600+ await md_store . load_blocks_for_chunks ( [ chunk ] ) ;
601+
602+ assert ( Array . isArray ( chunk . frags [ 0 ] . blocks ) ) ;
603+ assert ( chunk . frags [ 0 ] . blocks . length === 0 ) ;
604+ } ) ;
605+
606+ mocha . it ( 'excludes deleted blocks' , async function ( ) {
607+ if ( config . DB_TYPE !== 'postgres' ) return ;
608+ const bid = md_store . make_md_id ( ) ;
609+ const chunk = {
610+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
611+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
612+ } ;
613+ const live_block = {
614+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
615+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 10 ,
616+ } ;
617+ const deleted_block = {
618+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
619+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 10 ,
620+ } ;
621+ await md_store . insert_chunks ( [ chunk ] ) ;
622+ await md_store . insert_blocks ( [ live_block , deleted_block ] ) ;
623+ await md_store . delete_blocks_by_ids ( [ deleted_block . _id ] ) ;
624+
625+ await md_store . load_blocks_for_chunks ( [ chunk ] ) ;
626+
627+ assert ( chunk . frags [ 0 ] . blocks . length === 1 ) ;
628+ assert ( chunk . frags [ 0 ] . blocks [ 0 ] . _id . toString ( ) === live_block . _id . toString ( ) ) ;
629+ } ) ;
630+
631+ mocha . it ( 'applies sorter when provided' , async function ( ) {
632+ if ( config . DB_TYPE !== 'postgres' ) return ;
633+ const bid = md_store . make_md_id ( ) ;
634+ const chunk = {
635+ _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
636+ frags : [ { _id : md_store . make_md_id ( ) } ] , size : 10 , frag_size : 10 ,
637+ } ;
638+ const blocks = [
639+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
640+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 300 } ,
641+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
642+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 100 } ,
643+ { _id : md_store . make_md_id ( ) , system : system_id , bucket : bid ,
644+ node : md_store . make_md_id ( ) , chunk : chunk . _id , frag : chunk . frags [ 0 ] . _id , size : 200 } ,
645+ ] ;
646+ await md_store . insert_chunks ( [ chunk ] ) ;
647+ await md_store . insert_blocks ( blocks ) ;
648+
649+ const sorter = ( a , b ) => a . size - b . size ;
650+ await md_store . load_blocks_for_chunks ( [ chunk ] , sorter ) ;
651+
652+ const sizes = chunk . frags [ 0 ] . blocks . map ( b => b . size ) ;
653+ assert . deepStrictEqual ( sizes , [ 100 , 200 , 300 ] ) ;
654+ } ) ;
655+
656+ mocha . it ( 'returns early on empty input' , async function ( ) {
657+ await md_store . load_blocks_for_chunks ( [ ] ) ;
658+ await md_store . load_blocks_for_chunks ( null ) ;
659+ await md_store . load_blocks_for_chunks ( undefined ) ;
660+ } ) ;
661+ } ) ;
662+
436663 mocha . describe ( 'dedup-index' , function ( ) {
437664 mocha . it ( 'get_dedup_index_size()' , async function ( ) {
438665 return md_store . get_dedup_index_size ( ) ;
0 commit comments