# 매니페스트 쪽 TTL MongoIndexManifest.java:28 String partialFilterExpression, MongoIndexManifest.java:29 String collationProfile, MongoIndexManifest.java:30 Duration expireAfter, MongoIndexManifest.java:31 String wildcardProjection, MongoIndexManifest.java:32 boolean shardKeySupport, MongoIndexManifest.java:50 } MongoIndexManifest.java:51 if (keys.isEmpty()) { MongoIndexManifest.java:52 throw new IllegalArgumentException("index '" + name + "' declares no keys"); MongoIndexManifest.java:53 } MongoIndexManifest.java:54 if (expireAfter != null && expireAfter.isNegative()) { MongoIndexManifest.java:55 throw new IllegalArgumentException("index '" + name + "' declares a negative TTL"); MongoIndexManifest.java:56 } MongoIndexManifest.java:57 if (metadataOwnership == MongoMetadataOwnership.APPLICATION && expectedUsage.isEmpty()) { MongoIndexManifest.java:58 throw new IllegalArgumentException( MongoIndexManifest.java:66 /** Starts an index declaration. */ MongoIndexManifest.java:67 public static Builder named(String name) { MongoIndexManifest.java:68 return new Builder(name); MongoIndexManifest.java:69 } MongoIndexManifest.java:70 MongoIndexManifest.java:71 /** The TTL, when this is a TTL index. */ MongoIndexManifest.java:72 public Optional ttl() { MongoIndexManifest.java:73 return Optional.ofNullable(expireAfter); MongoIndexManifest.java:74 } MongoIndexManifest.java:75 MongoIndexManifest.java:76 /** True when this index is a TTL index. */ MongoIndexManifest.java:77 public boolean isTtlIndex() { MongoIndexManifest.java:78 return expireAfter != null; MongoIndexManifest.java:79 } MongoIndexManifest.java:80 MongoIndexManifest.java:186 } MongoIndexManifest.java:187 MongoIndexManifest.java:188 /** Declares this a TTL index with the given retention. */ MongoIndexManifest.java:189 public Builder expireAfter(Duration retention) { MongoIndexManifest.java:190 this.expireAfter = Objects.requireNonNull(retention, "retention"); MongoIndexManifest.java:191 return this; MongoIndexManifest.java:192 } MongoIndexManifest.java:193 MongoIndexManifest.java:194 /** Declares a wildcard projection, as canonical extended JSON. */ expireAfter 라는 이름이 그 파일에 나오는 줄 : 8 개 그중 값을 거절하는 줄 : 1 개 # 규칙을 가진 쪽 MongoTtlPolicyValidator.java:7 /** MongoTtlPolicyValidator.java:8 * Rejects the two ways a TTL index is misused (design §21.1, D-13). MongoTtlPolicyValidator.java:9 * MongoTtlPolicyValidator.java:10 *

The first is treating it as a scheduler: the TTL monitor's sweep interval is unspecified and MongoTtlPolicyValidator.java:11 * load-dependent, so "delete this at 09:00" is not something it promises. The second is relying on MongoTtlPolicyValidator.java:12 * it for access control: a document that still exists is still readable, so if expiry must hide MongoTtlPolicyValidator.java:13 * data the read has to say so. MongoTtlPolicyValidator.java:14 */ MongoTtlPolicyValidator.java:15 public final class MongoTtlPolicyValidator { MongoTtlPolicyValidator.java:16 MongoTtlPolicyValidator.java:17 /** MongoTtlPolicyValidator.java:18 * A TTL reduction below this threshold would expire a large population in one sweep, turning a MongoTtlPolicyValidator.java:19 * configuration change into an unplanned bulk delete. MongoTtlPolicyValidator.java:20 */ MongoTtlPolicyValidator.java:21 public static final Duration MINIMUM_SAFE_RETENTION = Duration.ofMinutes(1); MongoTtlPolicyValidator.java:22 MongoTtlPolicyValidator.java:23 /** MongoTtlPolicyValidator.java:24 * Validates one TTL policy. MongoTtlPolicyValidator.java:25 * MongoTtlPolicyValidator.java:26 * @throws MongoOperationRejectedException when the policy claims a guarantee TTL does not provide MongoTtlPolicyValidator.java:27 */ MongoTtlPolicyValidator.java:28 public void validate(MongoTtlPolicy policy) { MongoTtlPolicyValidator.java:29 Objects.requireNonNull(policy, "policy"); MongoTtlPolicyValidator.java:30 if (policy.claimsExactExpiry()) { MongoTtlPolicyValidator.java:31 throw MongoOperationRejectedException.of( MongoTtlPolicyValidator.java:32 "ttl.policy", MongoTtlPolicyValidator.java:33 "the TTL policy on '" MongoTtlPolicyValidator.java:34 + policy.field() MongoTtlPolicyValidator.java:35 + "' claims an exact business transition; MongoDB's TTL monitor sweeps on an " MongoTtlPolicyValidator.java:36 + "unspecified interval, so an exact transition needs its own scheduler and the TTL " MongoTtlPolicyValidator.java:37 + "index stays physical cleanup"); MongoTtlPolicyValidator.java:38 } MongoTtlPolicyValidator.java:39 if (!policy.queryChecksLogicalExpiry()) { MongoTtlPolicyValidator.java:40 throw MongoOperationRejectedException.of( MongoTtlPolicyValidator.java:41 "ttl.policy", MongoTtlPolicyValidator.java:42 "the TTL policy on '" MongoTtlPolicyValidator.java:43 + policy.field() MongoTtlPolicyValidator.java:44 + "' does not declare a query-time expiry check; an expired document remains readable " MongoTtlPolicyValidator.java:45 + "until the monitor deletes it, so reads must filter on " MongoTtlPolicyValidator.java:46 + policy.field() MongoTtlPolicyValidator.java:47 + " > applicationNow"); MongoTtlPolicyValidator.java:48 } MongoTtlPolicyValidator.java:49 if (!policy.retention().isZero() && policy.retention().compareTo(MINIMUM_SAFE_RETENTION) < 0) { MongoTtlPolicyValidator.java:50 throw MongoOperationRejectedException.of( MongoTtlPolicyValidator.java:51 "ttl.policy", MongoTtlPolicyValidator.java:52 "a TTL retention of " MongoTtlPolicyValidator.java:53 + policy.retention() MongoTtlPolicyValidator.java:54 + " is below the safe minimum of " MongoTtlPolicyValidator.java:55 + MINIMUM_SAFE_RETENTION MongoTtlPolicyValidator.java:56 + "; it would expire the existing population in a single sweep"); MongoTtlPolicyValidator.java:57 } MongoTtlPolicyValidator.java:58 } MongoTtlPolicyValidator.java:59 MongoTtlPolicyValidator.java:60 /** MongoTtlPolicyValidator.java:61 * Validates a TTL index descriptor, including the BSON type of its expiry field. MongoTtlPolicyValidator.java:62 * MongoTtlPolicyValidator.java:63 * @throws MongoOperationRejectedException when the field type cannot be expired MongoTtlPolicyValidator.java:64 */ MongoTtlPolicyValidator.java:65 public void validate(MongoTtlIndexDescriptor descriptor) { MongoTtlPolicyValidator.java:66 Objects.requireNonNull(descriptor, "descriptor"); MongoTtlPolicyValidator.java:67 validate(descriptor.policy()); MongoTtlPolicyValidator.java:68 if (!descriptor.expiryFieldTypeIsSupported()) { MongoTtlPolicyValidator.java:69 throw MongoOperationRejectedException.of( MongoTtlPolicyValidator.java:70 "ttl.policy", MongoTtlPolicyValidator.java:71 "TTL index '" MongoTtlPolicyValidator.java:72 + descriptor.indexName() MongoTtlPolicyValidator.java:73 + "' expires on a field stored as " MongoTtlPolicyValidator.java:74 + descriptor.expiryFieldBsonType() MongoTtlPolicyValidator.java:75 + "; MongoDB only expires BSON date fields and ignores the rest silently"); MongoTtlPolicyValidator.java:76 } MongoTtlPolicyValidator.java:77 } MongoTtlPolicyValidator.java:78 MongoTtlPolicyValidator.java:79 /** MongoTtlPolicyValidator.java:80 * Validates the read-side predicate that gives expiry its actual guarantee. MongoTtlPolicyValidator.java:81 * MongoTtlPolicyValidator.java:82 * @throws MongoOperationRejectedException when reads do not filter on logical expiry MongoTtlPolicyValidator.java:83 */ MongoTtlPolicyValidator.java:84 public void validate(MongoExpirationAccessPolicy accessPolicy) { MongoTtlPolicyValidator.java:85 Objects.requireNonNull(accessPolicy, "accessPolicy"); MongoTtlPolicyValidator.java:86 if (!accessPolicy.applied()) { MongoTtlPolicyValidator.java:87 throw MongoOperationRejectedException.of( MongoTtlPolicyValidator.java:88 "ttl.access", MongoTtlPolicyValidator.java:89 "reads of this collection do not apply '" MongoTtlPolicyValidator.java:90 + accessPolicy.describePredicate() MongoTtlPolicyValidator.java:91 + "', so an expired document stays visible until the TTL monitor happens to delete it"); MongoTtlPolicyValidator.java:92 } MongoTtlPolicyValidator.java:93 } MongoTtlPolicyValidator.java:94 } # 그 정책 타입이 요구하는 것 MongoTtlPolicy.java:1 package dev.caskeleton.adapter.outbound.mongo.schema.ttl; MongoTtlPolicy.java:2 MongoTtlPolicy.java:3 import java.time.Duration; MongoTtlPolicy.java:4 import java.util.Objects; MongoTtlPolicy.java:5 MongoTtlPolicy.java:6 /** MongoTtlPolicy.java:7 * What a TTL index is being used for (design §21.1, D-13). MongoTtlPolicy.java:8 * MongoTtlPolicy.java:9 *

MongoDB's TTL monitor runs roughly once a minute and deletes in batches, so an expired MongoTtlPolicy.java:10 * document stays readable for an unspecified interval after its expiry — longer under load, longer MongoTtlPolicy.java:11 * still on a busy secondary. That is fine for reclaiming space and wrong for anything that must MongoTtlPolicy.java:12 * stop being visible at a particular moment. MongoTtlPolicy.java:13 * MongoTtlPolicy.java:14 *

Both booleans are therefore part of the declaration. {@code physicalCleanupOnly} says the TTL MongoTtlPolicy.java:15 * is only reclaiming space; {@code queryChecksLogicalExpiry} says the application filters on {@code MongoTtlPolicy.java:16 * expiresAt > now} so visibility does not depend on the monitor's timing. MongoTtlPolicy.java:17 */ MongoTtlPolicy.java:18 public record MongoTtlPolicy( MongoTtlPolicy.java:19 String field, MongoTtlPolicy.java:20 Duration retention, MongoTtlPolicy.java:21 boolean physicalCleanupOnly, MongoTtlPolicy.java:22 boolean queryChecksLogicalExpiry) { MongoTtlPolicy.java:23 MongoTtlPolicy.java:24 public MongoTtlPolicy { MongoTtlPolicy.java:25 Objects.requireNonNull(field, "field"); MongoTtlPolicy.java:26 Objects.requireNonNull(retention, "retention"); MongoTtlPolicy.java:27 if (field.isBlank()) { MongoTtlPolicy.java:28 throw new IllegalArgumentException("a TTL policy needs an expiry field"); MongoTtlPolicy.java:29 } MongoTtlPolicy.java:30 if (retention.isNegative()) { MongoTtlPolicy.java:31 throw new IllegalArgumentException("a TTL retention must not be negative"); MongoTtlPolicy.java:32 } MongoTtlPolicy.java:33 } MongoTtlPolicy.java:34 MongoTtlPolicy.java:35 /** The supported shape: physical cleanup, with the application filtering on logical expiry. */ MongoTtlPolicy.java:36 public static MongoTtlPolicy physicalCleanup(String field, Duration retention) { MongoTtlPolicy.java:37 return new MongoTtlPolicy(field, retention, true, true); MongoTtlPolicy.java:38 } MongoTtlPolicy.java:39 MongoTtlPolicy.java:40 /** # 두 표현 사이에 참조가 있는가 schema/ttl 밖 main 에서 그 네 타입을 언급하는 줄 : 0 개 [대조] schema/ttl 안에서는 : 22 개 MongoIndexManifest 가 그 네 타입을 언급하는 줄 : 0 개 isTtlIndex() 나 ttl() 을 부르는 줄 : 0 개 [대조] 그 두 이름이 나오는 줄 (선언 포함) : 2 개 # 두 표현을 조립하는 main 코드가 있는가 MongoIndexManifest 를 만드는 main 줄 : 1 개 MongoIndexManifest.java:226 return new MongoIndexManifest( [대조] 시험에서 만드는 줄 : 7 개 MongoTtlPolicyValidator 를 만드는 main 줄 : 0 개 [대조] 시험에서 검증기를 만드는 줄 : 1 개