@@ -26,7 +26,7 @@ import type {
26
26
bson ,
27
27
} from '@mongosh/service-provider-core' ;
28
28
import type { ClientSideFieldLevelEncryptionOptions } from './field-level-encryption' ;
29
- import { type AutoEncryptionOptions } from 'mongodb' ;
29
+ import type { AutoEncryptionOptions , Long , ObjectId , Timestamp } from 'mongodb' ;
30
30
import { shellApiType } from './enums' ;
31
31
import type { AbstractCursor } from './abstract-cursor' ;
32
32
import type ChangeStreamCursor from './change-stream-cursor' ;
@@ -226,8 +226,8 @@ export function processDigestPassword(
226
226
export async function getPrintableShardStatus (
227
227
configDB : Database ,
228
228
verbose : boolean
229
- ) : Promise < Document > {
230
- const result = { } as any ;
229
+ ) : Promise < ShardingStatusResult > {
230
+ const result = { } as ShardingStatusResult ;
231
231
232
232
// configDB is a DB object that contains the sharding metadata of interest.
233
233
const mongosColl = configDB . getCollection ( 'mongos' ) ;
@@ -259,9 +259,12 @@ export async function getPrintableShardStatus(
259
259
) ;
260
260
}
261
261
262
- result . shardingVersion = version ;
262
+ result . shardingVersion = version as {
263
+ _id : number ;
264
+ clusterId : ObjectId ;
265
+ } ;
263
266
264
- result . shards = shards ;
267
+ result . shards = shards as ShardingStatusResult [ 'shards' ] ;
265
268
266
269
// (most recently) active mongoses
267
270
const mongosActiveThresholdMs = 60000 ;
@@ -280,9 +283,8 @@ export async function getPrintableShardStatus(
280
283
}
281
284
}
282
285
283
- mongosAdjective = `${ mongosAdjective } mongoses` ;
284
286
if ( mostRecentMongosTime === null ) {
285
- result [ mongosAdjective ] = 'none' ;
287
+ result [ ` ${ mongosAdjective } mongoses` ] = 'none' ;
286
288
} else {
287
289
const recentMongosQuery = {
288
290
ping : {
@@ -295,25 +297,27 @@ export async function getPrintableShardStatus(
295
297
} ;
296
298
297
299
if ( verbose ) {
298
- result [ mongosAdjective ] = await ( await mongosColl . find ( recentMongosQuery ) )
300
+ result [ `${ mongosAdjective } mongoses` ] = await (
301
+ await mongosColl . find ( recentMongosQuery )
302
+ )
299
303
. sort ( { ping : - 1 } )
300
304
. toArray ( ) ;
301
305
} else {
302
- result [ mongosAdjective ] = (
306
+ result [ ` ${ mongosAdjective } mongoses` ] = (
303
307
( await (
304
308
await mongosColl . aggregate ( [
305
309
{ $match : recentMongosQuery } ,
306
310
{ $group : { _id : '$mongoVersion' , num : { $sum : 1 } } } ,
307
311
{ $sort : { num : - 1 } } ,
308
312
] )
309
- ) . toArray ( ) ) as any [ ]
313
+ ) . toArray ( ) ) as { _id : string ; num : number } [ ]
310
314
) . map ( ( z : { _id : string ; num : number } ) => {
311
315
return { [ z . _id ] : z . num } ;
312
316
} ) ;
313
317
}
314
318
}
315
319
316
- const balancerRes : Record < string , any > = { } ;
320
+ const balancerRes = { } as ShardingStatusResult [ 'balancer' ] ;
317
321
await Promise . all ( [
318
322
( async ( ) : Promise < void > => {
319
323
// Is autosplit currently enabled
@@ -331,13 +335,13 @@ export async function getPrintableShardStatus(
331
335
} ) ( ) ,
332
336
( async ( ) : Promise < void > => {
333
337
// Is the balancer currently active
334
- let balancerRunning = 'unknown' ;
338
+ let balancerRunning : 'yes' | 'no' | 'unknown' = 'unknown' ;
335
339
try {
336
340
const balancerStatus = await configDB . adminCommand ( {
337
341
balancerStatus : 1 ,
338
342
} ) ;
339
343
balancerRunning = balancerStatus . inBalancerRound ? 'yes' : 'no' ;
340
- } catch ( err : any ) {
344
+ } catch {
341
345
// pass, ignore all error messages
342
346
}
343
347
balancerRes [ 'Currently running' ] = balancerRunning ;
@@ -364,7 +368,7 @@ export async function getPrintableShardStatus(
364
368
if ( activeLocks ?. length > 0 ) {
365
369
balancerRes [ 'Collections with active migrations' ] = activeLocks . map (
366
370
( lock ) => {
367
- return `${ lock . _id } started at ${ lock . when } ` ;
371
+ return `${ lock . _id } started at ${ lock . when } ` as const ;
368
372
}
369
373
) ;
370
374
}
@@ -418,8 +422,23 @@ export async function getPrintableShardStatus(
418
422
const yesterday = new Date ( ) ;
419
423
yesterday . setDate ( yesterday . getDate ( ) - 1 ) ;
420
424
425
+ type MigrationResult =
426
+ | {
427
+ _id : 'Success' ;
428
+ count : number ;
429
+ from : never ;
430
+ to : never ;
431
+ }
432
+ // Failed migration
433
+ | {
434
+ _id : string ;
435
+ count : number ;
436
+ from : string ;
437
+ to : string ;
438
+ } ;
439
+
421
440
// Successful migrations.
422
- let migrations = await (
441
+ let migrations = ( await (
423
442
await changelogColl . aggregate ( [
424
443
{
425
444
$match : {
@@ -437,11 +456,11 @@ export async function getPrintableShardStatus(
437
456
} ,
438
457
} ,
439
458
] )
440
- ) . toArray ( ) ;
459
+ ) . toArray ( ) ) as MigrationResult [ ] ;
441
460
442
461
// Failed migrations.
443
462
migrations = migrations . concat (
444
- await (
463
+ ( await (
445
464
await changelogColl . aggregate ( [
446
465
{
447
466
$match : {
@@ -472,11 +491,12 @@ export async function getPrintableShardStatus(
472
491
} ,
473
492
} ,
474
493
] )
475
- ) . toArray ( )
494
+ ) . toArray ( ) ) as MigrationResult [ ]
476
495
) ;
477
496
478
- const migrationsRes : Record < number , string > = { } ;
479
- migrations . forEach ( ( x : any ) => {
497
+ const migrationsRes : ShardingStatusResult [ 'balancer' ] [ 'Migration Results for the last 24 hours' ] =
498
+ { } ;
499
+ migrations . forEach ( ( x ) => {
480
500
if ( x . _id === 'Success' ) {
481
501
migrationsRes [ x . count ] = x . _id ;
482
502
} else {
@@ -500,7 +520,7 @@ export async function getPrintableShardStatus(
500
520
// All databases in config.databases + those implicitly referenced
501
521
// by a sharded collection in config.collections
502
522
// (could become a single pipeline using $unionWith when we drop 4.2 server support)
503
- const [ databases , collections ] = await Promise . all ( [
523
+ const [ databases , collections , shardedDataDistribution ] = await Promise . all ( [
504
524
( async ( ) =>
505
525
await ( await configDB . getCollection ( 'databases' ) . find ( ) )
506
526
. sort ( { _id : 1 } )
@@ -513,7 +533,22 @@ export async function getPrintableShardStatus(
513
533
)
514
534
. sort ( { _id : 1 } )
515
535
. toArray ( ) ) ( ) ,
536
+ ( async ( ) => {
537
+ try {
538
+ // $shardedDataDistribution is available since >= 6.0.3
539
+ const adminDB = configDB . getSiblingDB ( 'admin' ) ;
540
+ return ( await (
541
+ await adminDB . aggregate ( [ { $shardedDataDistribution : { } } ] )
542
+ ) . toArray ( ) ) as ShardedDataDistribution ;
543
+ } catch {
544
+ // Pass, most likely an older version.
545
+ return undefined ;
546
+ }
547
+ } ) ( ) ,
516
548
] ) ;
549
+
550
+ result . shardedDataDistribution = shardedDataDistribution ;
551
+
517
552
// Special case the config db, since it doesn't have a record in config.databases.
518
553
databases . push ( { _id : 'config' , primary : 'config' , partitioned : true } ) ;
519
554
@@ -648,6 +683,65 @@ export async function getPrintableShardStatus(
648
683
return result ;
649
684
}
650
685
686
+ export type ShardingStatusResult = {
687
+ shardingVersion : {
688
+ _id : number ;
689
+ clusterId : ObjectId ;
690
+ /** This gets deleted when it is returned from getPrintableShardStatus */
691
+ currentVersion ?: number ;
692
+ } ;
693
+ shards : {
694
+ _id : string ;
695
+ host : string ;
696
+ state : number ;
697
+ tags : string [ ] ;
698
+ topologyTime : Timestamp ;
699
+ replSetConfigVersion : Long ;
700
+ } [ ] ;
701
+ [ mongoses : `${string } mongoses`] :
702
+ | 'none'
703
+ | {
704
+ [ version : string ] :
705
+ | number
706
+ | {
707
+ up : number ;
708
+ waiting : boolean ;
709
+ } ;
710
+ } [ ] ;
711
+ autosplit : {
712
+ 'Currently enabled' : 'yes' | 'no' ;
713
+ } ;
714
+ balancer : {
715
+ 'Currently enabled' : 'yes' | 'no' ;
716
+ 'Currently running' : 'yes' | 'no' | 'unknown' ;
717
+ 'Failed balancer rounds in last 5 attempts' : number ;
718
+ 'Migration Results for the last 24 hours' :
719
+ | 'No recent migrations'
720
+ | {
721
+ [ count : number ] :
722
+ | 'Success'
723
+ | `Failed with error '${string } ', from ${string } to ${string } `;
724
+ } ;
725
+ 'Balancer active window is set between' ?: `${string } and ${string } server local time`;
726
+ 'Last reported error' ?: string ;
727
+ 'Time of Reported error' ?: string ;
728
+ 'Collections with active migrations' ?: `${string } started at ${string } `[ ] ;
729
+ } ;
730
+ shardedDataDistribution ?: ShardedDataDistribution ;
731
+ databases : { database : Document ; collections : Document } [ ] ;
732
+ } ;
733
+
734
+ export type ShardedDataDistribution = {
735
+ ns : string ;
736
+ shards : {
737
+ shardName : string ;
738
+ numOrphanedDocs : number ;
739
+ numOwnedDocuments : number ;
740
+ orphanedSizeBytes : number ;
741
+ ownedSizeBytes : number ;
742
+ } [ ] ;
743
+ } [ ] ;
744
+
651
745
export async function getConfigDB ( db : Database ) : Promise < Database > {
652
746
const helloResult = await db . _maybeCachedHello ( ) ;
653
747
if ( helloResult . msg !== 'isdbgrid' ) {
0 commit comments