@@ -3,6 +3,11 @@ import * as fs from 'node:fs';
33import path from 'node:path' ;
44import process from 'node:process' ;
55import { threadId } from 'node:worker_threads' ;
6+ import {
7+ type Counter ,
8+ getUniqueInstanceId ,
9+ getUniqueTimeId ,
10+ } from './process-id.js' ;
611
712/**
813 * Codec for encoding/decoding values to/from strings for WAL storage.
@@ -375,6 +380,13 @@ export function setCoordinatorProcess(
375380// eslint-disable-next-line functional/no-let
376381let shardCount = 0 ;
377382
383+ /**
384+ * Simple counter implementation for generating sequential IDs.
385+ */
386+ const shardCounter : Counter = {
387+ next : ( ) => ++ shardCount ,
388+ } ;
389+
378390/**
379391 * Generates a unique sharded WAL ID based on performance time origin, process ID, thread ID, and instance count.
380392 */
@@ -383,60 +395,6 @@ function getShardedWalId() {
383395 return `${ Math . round ( performance . timeOrigin ) } .${ process . pid } .${ threadId } .${ ++ ShardedWal . instanceCount } ` ;
384396}
385397
386- /**
387- * Generates a human-readable shard ID.
388- * This ID is unique per process/thread/shard combination and used in the file name.
389- * Format: readable-timestamp.pid.threadId.shardCount
390- * Example: "20240101-120000-000.12345.1.1"
391- * Becomes file: trace.20240101-120000-000.12345.1.1.log
392- */
393- export function getShardId ( ) : string {
394- const timestamp = Math . round ( performance . timeOrigin + performance . now ( ) ) ;
395- const readableTimestamp = sortableReadableDateString ( `${ timestamp } ` ) ;
396- return `${ readableTimestamp } .${ process . pid } .${ threadId } .${ ++ shardCount } ` ;
397- }
398-
399- /**
400- * Generates a human-readable sharded group ID.
401- * This ID is a globally unique, sortable, human-readable date string per run.
402- * Used directly as the folder name to group shards.
403- * Format: yyyymmdd-hhmmss-ms
404- * Example: "20240101-120000-000"
405- */
406- export function getShardedGroupId ( ) : string {
407- return sortableReadableDateString (
408- `${ Math . round ( performance . timeOrigin + performance . now ( ) ) } ` ,
409- ) ;
410- }
411-
412- /**
413- * Regex patterns for validating WAL ID formats
414- */
415- export const WAL_ID_PATTERNS = {
416- /** Readable date format: yyyymmdd-hhmmss-ms */
417- READABLE_DATE : / ^ \d { 8 } - \d { 6 } - \d { 3 } $ / ,
418- /** Group ID format: yyyymmdd-hhmmss-ms */
419- GROUP_ID : / ^ \d { 8 } - \d { 6 } - \d { 3 } $ / ,
420- /** Shard ID format: readable-date.pid.threadId.count */
421- SHARD_ID : / ^ \d { 8 } - \d { 6 } - \d { 3 } (?: \. \d + ) { 3 } $ / ,
422- } as const ;
423-
424- export function sortableReadableDateString ( timestampMs : string ) : string {
425- const timestamp = Number . parseInt ( timestampMs , 10 ) ;
426- const date = new Date ( timestamp ) ;
427- const MILLISECONDS_PER_SECOND = 1000 ;
428- const yyyy = date . getFullYear ( ) ;
429- const mm = String ( date . getMonth ( ) + 1 ) . padStart ( 2 , '0' ) ;
430- const dd = String ( date . getDate ( ) ) . padStart ( 2 , '0' ) ;
431- const hh = String ( date . getHours ( ) ) . padStart ( 2 , '0' ) ;
432- const min = String ( date . getMinutes ( ) ) . padStart ( 2 , '0' ) ;
433- const ss = String ( date . getSeconds ( ) ) . padStart ( 2 , '0' ) ;
434- // eslint-disable-next-line @typescript-eslint/no-magic-numbers
435- const ms = String ( timestamp % MILLISECONDS_PER_SECOND ) . padStart ( 3 , '0' ) ;
436-
437- return `${ yyyy } ${ mm } ${ dd } -${ hh } ${ min } ${ ss } -${ ms } ` ;
438- }
439-
440398/**
441399 * Ensures a directory exists, creating it recursively if necessary using sync methods.
442400 * @param dirPath - The directory path to ensure exists
@@ -491,7 +449,7 @@ export function getShardedFinalPath<T extends object | string = object>(opt: {
491449export class ShardedWal < T extends object | string = object > {
492450 static instanceCount = 0 ;
493451 readonly #id: string = getShardedWalId ( ) ;
494- readonly groupId = getShardedGroupId ( ) ;
452+ readonly groupId = getUniqueTimeId ( ) ;
495453 readonly #format: WalFormat < T > ;
496454 readonly #dir: string = process . cwd ( ) ;
497455 readonly #isCoordinator: boolean ;
@@ -511,7 +469,7 @@ export class ShardedWal<T extends object | string = object> {
511469 coordinatorIdEnvVar : string ;
512470 } ) {
513471 const { dir, format, groupId, coordinatorIdEnvVar } = opt ;
514- this . groupId = groupId ?? getShardedGroupId ( ) ;
472+ this . groupId = groupId ?? getUniqueTimeId ( ) ;
515473 if ( dir ) {
516474 this . #dir = dir ;
517475 }
@@ -531,7 +489,7 @@ export class ShardedWal<T extends object | string = object> {
531489 return this . #isCoordinator;
532490 }
533491
534- shard ( shardId : string = getShardId ( ) ) {
492+ shard ( shardId : string = getUniqueInstanceId ( shardCounter ) ) {
535493 return new WriteAheadLogFile ( {
536494 file : getShardedPath ( {
537495 dir : this . #dir,
0 commit comments