@@ -6,7 +6,7 @@ import { ScopedTelemetry } from '../telemetry/ScopedTelemetry';
66import { Telemetry } from '../telemetry/TelemetryDecorator' ;
77import { TelemetryService } from '../telemetry/TelemetryService' ;
88import { pathToArtifact } from '../utils/ArtifactsDir' ;
9- import { DataStore , DataStoreFactory } from './DataStore' ;
9+ import { DataStore , DataStoreFactory , StoreName } from './DataStore' ;
1010import { encryptionStrategy } from './lmdb/Utils' ;
1111
1212const log = LoggerFactory . getLogger ( 'LMDB' ) ;
@@ -15,7 +15,7 @@ export class LMDBStore implements DataStore {
1515 private readonly telemetry : ScopedTelemetry ;
1616
1717 constructor (
18- private readonly name : string ,
18+ public readonly name : StoreName ,
1919 private readonly store : Database < unknown , string > ,
2020 ) {
2121 this . telemetry = TelemetryService . instance . get ( `LMDB.${ name } ` ) ;
@@ -55,20 +55,31 @@ export class LMDBStoreFactory implements DataStoreFactory {
5555 private readonly timeout : NodeJS . Timeout ;
5656 private readonly env : RootDatabase ;
5757
58- private readonly stores = new Map < string , LMDBStore > ( ) ;
58+ private readonly stores = new Map < StoreName , LMDBStore > ( ) ;
5959
60- constructor ( private readonly rootDir : string = pathToArtifact ( 'lmdb' ) ) {
61- log . info ( `Initializing LMDB at ${ rootDir } and version ${ Version } ` ) ;
60+ constructor (
61+ private readonly rootDir : string = pathToArtifact ( 'lmdb' ) ,
62+ storeNames : StoreName [ ] = [ StoreName . public_schemas , StoreName . sam_schemas ] ,
63+ ) {
6264 this . storePath = join ( rootDir , Version ) ;
65+
6366 this . env = open ( {
6467 path : this . storePath ,
65- maxDbs : 10 , // 10 max databases
66- mapSize : 100 * 1024 * 1024 , // 100MB max size
68+ maxDbs : 10 ,
69+ mapSize : TotalMaxDbSize ,
70+ remapChunks : true ,
71+ pageSize : 8192 ,
6772 encoding : Encoding ,
6873 encryptionKey : encryptionStrategy ( Version ) ,
6974 } ) ;
7075
71- log . info ( 'Setup LMDB guages' ) ;
76+ for ( const store of storeNames ) {
77+ const database = this . env . openDB < unknown , string > ( {
78+ name : store ,
79+ encoding : Encoding ,
80+ } ) ;
81+ this . stores . set ( store , new LMDBStore ( store , database ) ) ;
82+ }
7283 this . registerLMDBGauges ( ) ;
7384
7485 this . timeout = setTimeout (
@@ -77,44 +88,22 @@ export class LMDBStoreFactory implements DataStoreFactory {
7788 } ,
7889 2 * 60 * 1000 ,
7990 ) ;
91+
92+ log . info ( `Initialized LMDB ${ Version } at ${ rootDir } ` ) ;
8093 }
8194
82- getOrCreate ( store : string ) : DataStore {
83- let val = this . stores . get ( store ) ;
95+ get ( store : StoreName ) : DataStore {
96+ const val = this . stores . get ( store ) ;
8497 if ( val === undefined ) {
85- let database ;
86- this . env . transactionSync ( ( ) => {
87- database = this . env . openDB < unknown , string > ( {
88- name : store ,
89- encoding : Encoding ,
90- } ) ;
91- } ) ;
92-
93- if ( database === undefined ) {
94- throw new Error ( `Failed to open LMDB store ${ store } ` ) ;
95- }
96- val = new LMDBStore ( store , database ) ;
97- this . stores . set ( store , val ) ;
98+ throw new Error ( `Store ${ store } not found. Available stores: ${ [ ...this . stores . keys ( ) ] . join ( ', ' ) } ` ) ;
9899 }
99-
100100 return val ;
101101 }
102102
103103 storeNames ( ) : ReadonlyArray < string > {
104104 return [ ...this . stores . keys ( ) ] ;
105105 }
106106
107- stats ( ) : Record < string , StoreStatsType > {
108- const result : Record < string , StoreStatsType > = { } ;
109- result [ 'global' ] = stats ( this . env ) ;
110-
111- for ( const [ key , value ] of this . stores . entries ( ) ) {
112- result [ key ] = value . stats ( ) ;
113- }
114-
115- return result ;
116- }
117-
118107 async close ( ) : Promise < void > {
119108 // Clear the stores map but don't close individual stores
120109 // LMDB will close them when we close the environment
@@ -139,14 +128,31 @@ export class LMDBStoreFactory implements DataStoreFactory {
139128 }
140129
141130 private registerLMDBGauges ( ) : void {
131+ let totalMb = 0 ;
132+ const globalStat = stats ( this . env ) ;
142133 this . telemetry . registerGaugeProvider ( 'version' , ( ) => VersionNumber ) ;
143- this . telemetry . registerGaugeProvider ( 'global.size_mb ' , ( ) => stats ( this . env ) . totalSizeMB , { unit : 'MB' } ) ;
144- this . telemetry . registerGaugeProvider ( 'global.max_size_mb ' , ( ) => stats ( this . env ) . maxSizeMB , {
134+ this . telemetry . registerGaugeProvider ( 'global.size ' , ( ) => globalStat . totalSizeMB , { unit : 'MB' } ) ;
135+ this . telemetry . registerGaugeProvider ( 'global.max.size ' , ( ) => globalStat . maxSizeMB , {
145136 unit : 'MB' ,
146137 } ) ;
147- this . telemetry . registerGaugeProvider ( 'global.entries' , ( ) => stats ( this . env ) . entries ) ;
148- this . telemetry . registerGaugeProvider ( 'global.readers' , ( ) => stats ( this . env ) . numReaders ) ;
149- this . telemetry . registerGaugeProvider ( 'stores.count' , ( ) => this . stores . size ) ;
138+ this . telemetry . registerGaugeProvider ( 'global.entries' , ( ) => globalStat . entries ) ;
139+ totalMb += globalStat . totalSizeMB ;
140+
141+ for ( const [ name , store ] of this . stores . entries ( ) ) {
142+ const stat = store . stats ( ) ;
143+ totalMb += stat . totalSizeMB ;
144+
145+ this . telemetry . registerGaugeProvider ( `store.${ name } .size` , ( ) => stat . totalSizeMB , {
146+ unit : 'MB' ,
147+ } ) ;
148+ this . telemetry . registerGaugeProvider ( `store.${ name } .entries` , ( ) => stat . entries , {
149+ unit : 'MB' ,
150+ } ) ;
151+ }
152+
153+ this . telemetry . registerGaugeProvider ( 'global.usage' , ( ) => totalMb / TotalMaxDbSize , {
154+ unit : '%' ,
155+ } ) ;
150156 }
151157}
152158
@@ -157,6 +163,7 @@ function bytesToMB(bytes: number) {
157163const VersionNumber = 2 ;
158164const Version = `v${ VersionNumber } ` ;
159165const Encoding : 'msgpack' | 'json' | 'string' | 'binary' | 'ordered-binary' = 'msgpack' ;
166+ const TotalMaxDbSize = 250 * 1024 * 1024 ; // 250MB max size
160167
161168function stats ( store : RootDatabase | Database ) : StoreStatsType {
162169 const stats = store . getStats ( ) as Record < string , number > ;
0 commit comments