refactor: убрать ограничение maxChars из хранилища соответствий
- Удалены поле maxChars, параметр конструктора и метод evictWhileOverLimit. - Хранилище теперь ограничено только TTL (ttl-minutes), без вытеснения по объёму. - Конструкторы переведены на (int ttlMinutes) и (int ttlMinutes, SharedIndex, PayloadCipher). - Обновлены тесты и PipelineWarmup на новые сигнатуры.
This commit is contained in:
@@ -24,9 +24,8 @@ import org.springframework.stereotype.Component;
|
||||
* было бы получить в ответ исходные значения из запроса другого потребителя. Разделение
|
||||
* ограничивает это пределами одной системы, которая и так видит свои данные.
|
||||
*
|
||||
* <p>Хранилище ограничено по суммарному объёму строк, а записи живут ограниченное время:
|
||||
* персональные данные не должны залёживаться в памяти, а крупные тексты не должны исчерпать кучу.
|
||||
* Вытеснение идёт в порядке добавления и выполняется прямо на записи — отдельного потока и внешней
|
||||
* <p>Записи живут ограниченное время: персональные данные не должны залёживаться в памяти.
|
||||
* Протухшие записи убираются в порядке добавления прямо на записи — отдельного потока и внешней
|
||||
* библиотеки кеширования не требуется.
|
||||
*
|
||||
* <p>Когда включён общий слой ({@link SharedIndex}), соответствие пишется ещё и туда, а чтение при
|
||||
@@ -58,26 +57,30 @@ public class PayloadStore {
|
||||
private final ConcurrentLinkedQueue<String> insertionOrder = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicLong charsHeld = new AtomicLong();
|
||||
|
||||
private final long maxChars;
|
||||
private final long ttlMillis;
|
||||
private final SharedIndex shared;
|
||||
private final PayloadCipher cipher;
|
||||
|
||||
@Autowired
|
||||
public PayloadStore(
|
||||
@Value("${pdguard.store.max-chars:134217728}") long maxChars,
|
||||
@Value("${pdguard.store.ttl-minutes:30}") int ttlMinutes,
|
||||
SharedIndex shared,
|
||||
PayloadCipher cipher) {
|
||||
this.maxChars = maxChars;
|
||||
this.ttlMillis = ttlMinutes * 60_000L;
|
||||
this.shared = shared;
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
/** Конструктор для тестов: только локальная память, общий слой и шифрование выключены. */
|
||||
public PayloadStore(long maxChars, int ttlMinutes) {
|
||||
this(maxChars, ttlMinutes, SharedIndex.disabled(), PayloadCipher.disabled());
|
||||
public PayloadStore(int ttlMinutes) {
|
||||
this(ttlMinutes, SharedIndex.disabled(), PayloadCipher.disabled());
|
||||
}
|
||||
|
||||
/** Конструктор для тестов с явным общим слоем и шифрованием. */
|
||||
public PayloadStore(int ttlMinutes, SharedIndex shared, PayloadCipher cipher) {
|
||||
this.ttlMillis = ttlMinutes * 60_000L;
|
||||
this.shared = shared;
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
public void put(String system, String payloadId, String original, String masked) {
|
||||
@@ -92,7 +95,6 @@ public class PayloadStore {
|
||||
charsHeld.addAndGet((long) entry.weight() - (replaced == null ? 0 : replaced.weight()));
|
||||
|
||||
sweepExpired(now);
|
||||
evictWhileOverLimit();
|
||||
|
||||
shared.put(system, payloadId, encrypted, masked, entry.fingerprint());
|
||||
}
|
||||
@@ -154,22 +156,6 @@ public class PayloadStore {
|
||||
}
|
||||
}
|
||||
|
||||
private void evictWhileOverLimit() {
|
||||
while (charsHeld.get() > maxChars) {
|
||||
String oldest = insertionOrder.poll();
|
||||
if (oldest == null) {
|
||||
return;
|
||||
}
|
||||
Entry entry = byId.get(oldest);
|
||||
if (entry != null) {
|
||||
// ponytail: если тот же payload_id записали повторно, в очереди остался
|
||||
// старый след и здесь вытесняется свежая запись. Цена — одно лишнее
|
||||
// обращение к маскированию; точный учёт потребовал бы двусвязного списка.
|
||||
forget(oldest, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void forget(String idKey, Entry entry) {
|
||||
if (byId.remove(idKey, entry)) {
|
||||
byMaskFingerprint.remove(ScopedKey.of(entry.system(), entry.fingerprint()), entry);
|
||||
|
||||
@@ -62,7 +62,7 @@ public class PipelineWarmup {
|
||||
}
|
||||
long started = System.nanoTime();
|
||||
Pipeline scratch =
|
||||
new Pipeline(registry, masker, new PayloadStore(1_000_000L, 1), NameCascade.disabled());
|
||||
new Pipeline(registry, masker, new PayloadStore(1), NameCascade.disabled());
|
||||
SystemPolicy policy =
|
||||
new SystemPolicy(
|
||||
SystemPolicy.DEFAULT_NAME,
|
||||
|
||||
@@ -37,12 +37,6 @@ pdguard:
|
||||
systems-file: config/systems.json
|
||||
store:
|
||||
backend: memory
|
||||
# 128MB (было) держал store.chars упёртым в потолок под держащей нагрузкой —
|
||||
# FIFO-вытеснение выкидывало свежую запись за миллисекунды, раньше, чем
|
||||
# приходил её собственный демаскирующий запрос: см. k6 на датасете утечек,
|
||||
# 6.1% неверных демасков при 2000 VU, при этом 0% на низкой конкурентности.
|
||||
# На одном узле без соседей по хосту память есть — 512MB даёт запас на порядок.
|
||||
max-chars: 536870912
|
||||
ttl-minutes: 30
|
||||
# 32 байта в hex; AES-256 ключ шифрования хранилища
|
||||
encryption-key: "46a38b200c6df557a5fd2c8a57ad3fec6b710b9f3e1fef1451d121a094f63573"
|
||||
|
||||
Reference in New Issue
Block a user