- All Implemented Interfaces:
Runnable, KeyFactory
Started by ECIESAEADEngine. One type per-thread. Only used for 768, for now.
Nested Class Summary
Nested classes/interfaces inherited from class I2PThread
I2PThread.OOMEventListenerModifier and TypeClassDescriptionstatic interfaceListener for out-of-memory events.Nested classes/interfaces inherited from class Thread
Thread.Builder, Thread.State, Thread.UncaughtExceptionHandlerField Summary
FieldsModifier and TypeFieldDescriptionprivate intDelay between precalculation batches.private longDelay before checking the queue again.private final I2PAppContextThe app context.private final AtomicIntegerTimes the queue was found empty.private booleanTrue while the factory thread runs.private final LinkedBlockingQueue<KeyPair> Queue of the precalculated key pairs.private final LogLogger for the key precalculation.private intKeys kept in the queue at most.private intKeys kept in the queue at least.private final EncTypeThe ML-KEM parameter set generated.private final AtomicIntegerKeys taken from the queue.(package private) static final intThe byte budget expressed in keypairs.(package private) static final intApproximate heap size of one pooled ML-KEM-768 keypair, in bytes.private static final intDefault precalculation delay, in ms.private static final intDefault maximum queue size.private static final intDefault minimum queue size.private static final intLargest queue size allowed.private static MLKEMKeyFactoryThe factory created last, for reuse.(package private) static final longCeiling on the whole pool, in bytes.private static final StringConfig key for the precalculation delay.private static final StringConfig key for the maximum queue size.private static final StringConfig key for the minimum queue size.Fields inherited from class Thread
MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITYConstructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionprivate final booleanAdds a precomputed key pair to the pool.(package private) static intboundedPoolSize(int minSize, int demandMax, int cap) Bound a pool size: at least four above the floor, never above the cap.static intThe pool ceiling in keypairs thatsetMinSize(int)will accept.static MLKEMKeyFactoryThe most recently constructed factory.getKeys()Pulls a prebuilt keypair from the queue, or if not available, construct a new one.intUpper bound on the precalculated key queue size.intLower bound on the precalculated key queue size.intgetSize()Returns the current number of precalc keys queued.(package private) static intpoolFloor(int minSize, int cap) The smallest size the pool may be driven to: its floor, never above the cap.private KeyPairprecalc()Generates one key pair.(package private) static intpressureAdjustedMax(int maxSize, int minSize, int cap, double memPressure) Shrink the pool ceiling under memory pressure, without letting the shrink raise it past the byte budget on its way back down.voidCalled by the Tuner every 15 seconds.voidreturnUnused(KeyPair kp) Return an unused key pair to be put back onto the queue for reuse.voidrun()Run the thread, catching and reporting OOM and other failures.private voidrun2()Runs the precalculation loop.voidsetMaxSize(int max) Maximum precalc queue size.voidsetMinSize(int min) Minimum precalc queue size.voidshutdown()Note that this stops the singleton precalc thread.Methods inherited from class I2PThread
addOOMEventListener, fireOOM, removeOOMEventListener, startModifier and TypeMethodDescriptionstatic voidRegister a new component that wants notification of OOM events.protected voidfireOOM(OutOfMemoryError oom) Notify listeners that an OutOfMemoryError occurred.static voidUnregister a component that wants notification of OOM events.voidstart()Overridden to provide useful info to users on OOM, and to prevent shutting down the whole JVM for what is most likely not a heap issue.Methods inherited from class Thread
activeCount, clone, currentThread, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, isVirtual, join, join, join, join, ofPlatform, ofVirtual, onSpinWait, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, sleep, sleep, startVirtualThread, threadId, toString, yield
Field Details
lastInstance
The factory created last, for reuse._context
The app context._log
Logger for the key precalculation._minSize
private volatile int _minSizeKeys kept in the queue at least._maxSize
private volatile int _maxSizeKeys kept in the queue at most._calcDelay
private volatile int _calcDelayDelay between precalculation batches._keys
Queue of the precalculated key pairs._type
The ML-KEM parameter set generated._isRunning
private volatile boolean _isRunningTrue while the factory thread runs._checkDelay
private long _checkDelayDelay before checking the queue again._emptyCount
Times the queue was found empty._usedCount
Keys taken from the queue.PROP_MLKEM_PRECALC_MIN
Config key for the minimum queue size.- See Also:
PROP_MLKEM_PRECALC_MAX
Config key for the maximum queue size.- See Also:
PROP_MLKEM_PRECALC_DELAY
Config key for the precalculation delay.- See Also:
BYTES_PER_PAIR
static final int BYTES_PER_PAIRApproximate heap size of one pooled ML-KEM-768 keypair, in bytes. The pool scales with cores and memory, so the scaled defaults are capped by the byte budget below - an uncapped count scale can reach 100+ MB on high-core boxes.- See Also:
MAX_POOL_BYTES
DEFAULT_MLKEM_PRECALC_MIN
private static final int DEFAULT_MLKEM_PRECALC_MINDefault minimum queue size.- See Also:
DEFAULT_MLKEM_PRECALC_MAX
private static final int DEFAULT_MLKEM_PRECALC_MAXDefault maximum queue size.- See Also:
DEFAULT_MLKEM_PRECALC_DELAY
private static final int DEFAULT_MLKEM_PRECALC_DELAYDefault precalculation delay, in ms.- See Also:
HARD_MAX
BYTE_CAP
static final int BYTE_CAPThe byte budget expressed in keypairs. This, notHARD_MAX, is what bounds the pool - HARD_MAX alone would allow 32768 pairs, about 128 MB, which is what the demand-driven resize used to be able to reach.
Constructor Details
MLKEMKeyFactory
Alice side only.- Parameters:
ctx- the application context whose log, stat and system info are usedtype- must be one of the internal types MLKEM*_INT
Method Details
getByteCap
public static int getByteCap()The pool ceiling in keypairs thatsetMinSize(int)will accept.Public because the auto-tuner declares a range for this pool and must not propose a floor the setter silently rewrites; a target above this cap lands back on the current value and reads as a param that will not tune.
- Returns:
- the byte-budget cap expressed in keypairs
getInstance
The most recently constructed factory.- Returns:
- the most recently constructed factory, or null if none has been created yet
getMinSize
public int getMinSize()Lower bound on the precalculated key queue size.- Returns:
- the min size
setMinSize
public void setMinSize(int min) Minimum precalc queue size.- Parameters:
min- the floor on the queue, clamped into [1,BYTE_CAP] so a Tuner value cannot lift the floor past the byte budget
getMaxSize
public int getMaxSize()Upper bound on the precalculated key queue size.- Returns:
- the max size
setMaxSize
public void setMaxSize(int max) Maximum precalc queue size.- Parameters:
max- the ceiling on the queue, raised to the minimum if it is lower
getSize
public int getSize()Returns the current number of precalc keys queued.- Returns:
- the number of prebuilt keypairs currently waiting in the pool
boundedPoolSize
static int boundedPoolSize(int minSize, int demandMax, int cap) Bound a pool size: at least four above the floor, never above the cap.The floor is capped too, so a configured minimum larger than the cap cannot smuggle the pool past the byte budget by way of the floor.
Pure and static so the byte budget's reach can be pinned without running the precalc thread.
- Parameters:
minSize- the pool floor the pool must stay abovedemandMax- the size the caller wants, from demand or configurationcap- the ceiling, in keypairs- Returns:
- the size to use, always ≤ cap
poolFloor
static int poolFloor(int minSize, int cap) The smallest size the pool may be driven to: its floor, never above the cap. A floor set at the cap pins the pool there instead of letting every "at least min + 4" margin push it past the byte budget.- Parameters:
minSize- the pool floorcap- the ceiling, in keypairs- Returns:
- the effective floor, always ≤ cap
refreshPoolSize
public void refreshPoolSize()Called by the Tuner every 15 seconds. Adjusts max pool size based on demand.Demand is bounded by the byte budget, not by
HARD_MAX: the earlier bound let demand drive the pool to 32768 pairs, roughly 128 MB, and the memory-pressure halving below only engages above 70% pressure, so a router with a large heap could sit there indefinitely.pressureAdjustedMax
static int pressureAdjustedMax(int maxSize, int minSize, int cap, double memPressure) Shrink the pool ceiling under memory pressure, without letting the shrink raise it past the byte budget on its way back down.The floor of each shrink goes through
poolFloor(int, int), so a floor set at the budget cannot add its four-pair margin on top of the cap.Pure and static so the pressure branches can be pinned without driving the JVM's free-memory ratio.
- Parameters:
maxSize- the ceiling demand producedminSize- the pool floorcap- the ceiling, in keypairsmemPressure- the fraction of the heap in use, 0 to 1- Returns:
- the ceiling to use, never above cap
shutdown
public void shutdown()Note that this stops the singleton precalc thread. You don't want to do this if there are multiple routers in the JVM. Fix this if you care. SeeRouter.shutdown(int).run
run2
Runs the precalculation loop.- Throws:
GeneralSecurityException- if a key pair cannot be generated
getKeys
Pulls a prebuilt keypair from the queue, or if not available, construct a new one.- Specified by:
getKeysin interfaceKeyFactory- Returns:
- an ML-KEM keypair, taken from the prebuilt pool when one was available and generated on demand otherwise, never null
precalc
Generates one key pair.- Returns:
- the new key pair
- Throws:
GeneralSecurityException- if the generation fails
returnUnused
Return an unused key pair to be put back onto the queue for reuse.- Parameters:
kp- the pair that was taken from the queue but never used
addKeys
Adds a precomputed key pair to the pool.- Parameters:
kp- the key pair to add- Returns:
- true if successful, false if full