@@ -151,63 +151,75 @@ export type InternalListObjectParams = {
151151 gt ?: undefined ;
152152} ;
153153
154+ export interface UsedCapacityMetrics {
155+ current : Long | number ;
156+ nonCurrent : Long | number ;
157+ _currentCold : Long | number ;
158+ _nonCurrentCold : Long | number ;
159+ _currentRestored : Long | number ;
160+ _currentRestoring : Long | number ;
161+ _nonCurrentRestored : Long | number ;
162+ _nonCurrentRestoring : Long | number ;
163+ _incompleteMPUParts : Long | number ;
164+ // present on per-location and inflight-tagged bucket entries
165+ _inflightsPreScan ?: Long | number ;
166+ }
167+
168+ export interface ObjectCountMetrics {
169+ current : Long | number ;
170+ nonCurrent : Long | number ;
171+ deleteMarker : Long | number ;
172+ _currentCold : Long | number ;
173+ _nonCurrentCold : Long | number ;
174+ _currentRestored : Long | number ;
175+ _currentRestoring : Long | number ;
176+ _nonCurrentRestored : Long | number ;
177+ _nonCurrentRestoring : Long | number ;
178+ _incompleteMPUUploads : Long | number ;
179+ }
180+
154181export interface InfostoreDocument extends Document {
155182 _id : string | 'uuid' ;
156183 value ?: string | ObjectMDStats ;
157184 measuredOn ?: string ;
158- objectCount ?: {
159- current : Long | number ;
160- _currentCold : Long | number ;
161- deleteMarker : Long | number ;
162- nonCurrent : Long | number ;
163- _nonCurrentCold : Long | number ;
164- _currentRestored : Long | number ;
165- _currentRestoring : Long | number ;
166- _nonCurrentRestored : Long | number ;
167- _nonCurrentRestoring : Long | number ;
168- _incompleteMPUUploads : Long | number ;
169- } ;
170- usedCapacity ?: {
171- current : Long | number ;
172- _currentCold : Long | number ;
173- nonCurrent : Long | number ;
174- _nonCurrentCold : Long | number ;
175- _currentRestored : Long | number ;
176- _currentRestoring : Long | number ;
177- _nonCurrentRestored : Long | number ;
178- _nonCurrentRestoring : Long | number ;
179- _incompleteMPUParts : Long | number ;
180- } ;
185+ objectCount ?: ObjectCountMetrics ;
186+ usedCapacity ?: UsedCapacityMetrics ;
181187 locations : {
182188 [ key : string ] : {
183- usedCapacity : {
184- current : Long | number ;
185- nonCurrent : Long | number ;
186- _currentCold : Long | number ;
187- _nonCurrentCold : Long | number ;
188- _currentRestored : Long | number ;
189- _currentRestoring : Long | number ;
190- _nonCurrentRestored : Long | number ;
191- _nonCurrentRestoring : Long | number ;
192- _inflightsPreScan : Long | number ;
193- _incompleteMPUParts : Long | number ;
194- } ;
195- objectCount : {
196- current : Long | number ;
197- nonCurrent : Long | number ;
198- _currentCold : Long | number ;
199- _nonCurrentCold : Long | number ;
200- _currentRestored : Long | number ;
201- _currentRestoring : Long | number ;
202- _nonCurrentRestored : Long | number ;
203- _nonCurrentRestoring : Long | number ;
204- _incompleteMPUUploads : Long | number ;
205- deleteMarker : Long | number ;
206- } ;
189+ usedCapacity : UsedCapacityMetrics ;
190+ objectCount : ObjectCountMetrics ;
207191 } ;
208192 } ;
209193}
210194
195+ // Canonical zero-value capacity/count metrics for an empty bucket, matching the
196+ // structure downstream metric readers expect.
197+ const emptyBucketCapacityMetrics : { usedCapacity : UsedCapacityMetrics ; objectCount : ObjectCountMetrics } = {
198+ usedCapacity : {
199+ current : 0 ,
200+ nonCurrent : 0 ,
201+ _currentCold : 0 ,
202+ _nonCurrentCold : 0 ,
203+ _currentRestored : 0 ,
204+ _currentRestoring : 0 ,
205+ _nonCurrentRestored : 0 ,
206+ _nonCurrentRestoring : 0 ,
207+ _incompleteMPUParts : 0 ,
208+ } ,
209+ objectCount : {
210+ current : 0 ,
211+ nonCurrent : 0 ,
212+ deleteMarker : 0 ,
213+ _currentCold : 0 ,
214+ _nonCurrentCold : 0 ,
215+ _currentRestored : 0 ,
216+ _currentRestoring : 0 ,
217+ _nonCurrentRestored : 0 ,
218+ _nonCurrentRestoring : 0 ,
219+ _incompleteMPUUploads : 0 ,
220+ } ,
221+ } ;
222+
211223export type ObjectMDStats = {
212224 versions : number ;
213225 objects : any ;
@@ -2711,6 +2723,57 @@ class MongoClientInterface {
27112723 } ) ;
27122724 }
27132725
2726+ /**
2727+ * Initialize a zero-value bucket capacity metric document in the
2728+ * `__infostore` collection, unless one already exists. This lets quota
2729+ * checks be served for a freshly created (or newly quota-enabled empty)
2730+ * bucket before the periodic metrics job has produced real values.
2731+ *
2732+ * Idempotent: an existing document (e.g. one already holding real metrics)
2733+ * is never overwritten, thanks to `$setOnInsert`.
2734+ *
2735+ * @param bucketName - name of the bucket
2736+ * @param creationDate - bucket creation date used to build the metric id;
2737+ * must match the id the metrics job uses so lookups resolve to the same
2738+ * document
2739+ * @param log - logger instance
2740+ * @param cb - callback
2741+ * @returns undefined
2742+ */
2743+ initializeBucketCapacity (
2744+ bucketName : string ,
2745+ creationDate : string ,
2746+ log : werelogs . Logger ,
2747+ cb : ArsenalCallback < void > ,
2748+ ) {
2749+ const i = this . getCollection < InfostoreDocument > ( INFOSTORE ) ;
2750+ if ( ! i ) {
2751+ log . error ( 'initializeBucketCapacity: error getting infostore collection' ) ;
2752+ return cb ( errors . InternalError ) ;
2753+ }
2754+ const timestamp = new Date ( creationDate ) . getTime ( ) ;
2755+ if ( Number . isNaN ( timestamp ) ) {
2756+ log . error ( 'initializeBucketCapacity: invalid creationDate' , { bucketName, creationDate } ) ;
2757+ return cb ( errors . InternalError ) ;
2758+ }
2759+ const _id = `bucket_${ bucketName } _${ timestamp } ` ;
2760+ const doc = < InfostoreDocument > {
2761+ _id,
2762+ measuredOn : new Date ( ) . toJSON ( ) ,
2763+ ...emptyBucketCapacityMetrics ,
2764+ } ;
2765+ return i
2766+ . updateOne ( { _id } , { $setOnInsert : doc } , { upsert : true } )
2767+ . then ( ( ) => cb ( null ) )
2768+ . catch ( err => {
2769+ log . error ( 'initializeBucketCapacity: error initializing bucket capacity' , {
2770+ error : err . message ,
2771+ bucketName,
2772+ } ) ;
2773+ return cb ( errors . InternalError ) ;
2774+ } ) ;
2775+ }
2776+
27142777 /*
27152778 * we always try to generate a new UUID in order to be atomic in
27162779 * case of concurrency. The write will fail if it already exists.
0 commit comments