@@ -381,12 +381,18 @@ public static class OptOutStoreSnapshot {
381381 .description ("gauge for max entries can be cached in bloomfilter" )
382382 .register (Metrics .globalRegistry );
383383
384+ private static final Gauge GAUGE_OPTOUT_OLD_COUNT = Gauge
385+ .builder ("uid2_operator_optout_old_count" , () -> OptOutStoreSnapshot .oldCount .get ())
386+ .description ("gauge for number of unique optout entries older than threshold (configurable)" )
387+ .register (Metrics .globalRegistry );
388+
384389 // stores the timestamp of last updated delta or partition file
385390 private static final AtomicReference <Instant > lastUpdatedTimestamp = new AtomicReference <>(Instant .EPOCH );
386391 private static final AtomicLong bloomFilterSize = new AtomicLong (0 );
387392 private static final AtomicLong bloomFilterMax = new AtomicLong (0 );
388393 private static final AtomicLong totalEntries = new AtomicLong (0 );
389394 private static final AtomicInteger adIdCount = new AtomicInteger (0 );
395+ private static final AtomicLong oldCount = new AtomicLong (0 );
390396 private static final BiFunction <Long , Long , Long > OPT_OUT_TIMESTAMP_MERGE_STRATEGY = Long ::min ;
391397
392398 private final DownloadCloudStorage fsLocal ;
@@ -418,6 +424,8 @@ public static class OptOutStoreSnapshot {
418424
419425 private final Clock clock ;
420426
427+ private final long optOutOldCountThresholdSeconds ;
428+
421429 public OptOutStoreSnapshot (DownloadCloudStorage fsLocal , JsonObject jsonConfig , Clock clock ) {
422430 this .clock = clock ;
423431 this .fsLocal = fsLocal ;
@@ -436,6 +444,7 @@ public OptOutStoreSnapshot(DownloadCloudStorage fsLocal, JsonObject jsonConfig,
436444
437445 this .adIdToOptOutTimestamp = Collections .emptyMap ();
438446 this .optoutStatusApiEnabled = jsonConfig .getBoolean (Const .Config .OptOutStatusApiEnabled , true );
447+ this .optOutOldCountThresholdSeconds = jsonConfig .getLong (Const .Config .OptOutOldCountThresholdSecondsProp , 3600L ); // Default 1 hour
439448
440449 // initially 1 partition
441450 this .partitions = new OptOutPartition [1 ];
@@ -453,6 +462,7 @@ public OptOutStoreSnapshot(OptOutStoreSnapshot last, BloomFilter bf, OptOutHeap
453462 this .fsLocal = last .fsLocal ;
454463 this .fileUtils = last .fileUtils ;
455464 this .iteration = last .iteration + 1 ;
465+ this .optOutOldCountThresholdSeconds = last .optOutOldCountThresholdSeconds ;
456466
457467 this .bloomFilter = bf ;
458468 this .heap = heap ;
@@ -481,6 +491,7 @@ public OptOutStoreSnapshot(OptOutStoreSnapshot last, BloomFilter bf, OptOutHeap
481491 // update total entries
482492 totalEntries .set (size ());
483493 adIdCount .set (this .adIdToOptOutTimestamp .size ());
494+ oldCount .set (countOldRecords (this .optOutOldCountThresholdSeconds ));
484495 }
485496
486497 public long size () {
@@ -490,6 +501,22 @@ public long size() {
490501 .sum ();
491502 }
492503
504+ public long countOldRecords (long thresholdSeconds ) {
505+ long currentTimeSeconds = clock .instant ().getEpochSecond ();
506+ long cutoffTime = currentTimeSeconds - thresholdSeconds ;
507+
508+ Set <String > uniqueHashes = new HashSet <>();
509+ for (OptOutPartition partition : this .partitions ) {
510+ if (partition == null ) continue ;
511+ partition .forEach (entry -> {
512+ if (entry .timestamp < cutoffTime ) {
513+ uniqueHashes .add (entry .idHashToB64 ());
514+ }
515+ });
516+ }
517+ return uniqueHashes .size ();
518+ }
519+
493520 // method provided for OptOutService to assess health
494521 public boolean isHealthy (Instant now ) {
495522 // index is healthy if it is updated within 3 * logRotationInterval
0 commit comments