Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion foundation-store-contracts/gradle/owned-output-patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
network/crypta/store/StorableBlock*
network/crypta/store/BlockMetadata*
network/crypta/store/GetPubkey*

network/crypta/node/stats/StoreAccessStats*
network/crypta/node/stats/StatsNotAvailableException*
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@
* <li>Plugin-provided statistics while the plugin is missing, disabled, or reloading.
* </ul>
*
* @see network.crypta.node.stats.DataStoreStats
* @see network.crypta.node.stats.StoreAccessStats
* @author nikotyan
*/
@SuppressWarnings("unused")
public class StatsNotAvailableException extends Exception {

/** Serialization identifier for stable exception transport and persistence compatibility. */
@Serial private static final long serialVersionUID = -7349859507599514672L;

/**
Expand Down Expand Up @@ -65,7 +64,7 @@ public StatsNotAvailableException(String s) {
* and logging.
*
* @param s detail message describing the high-level condition; may be {@code null} if the cause
* is sufficiently descriptive on its own.
* is descriptive enough on its own.
* @param throwable the underlying cause that prevented providing statistics; may be {@code null}
* if unknown or not applicable.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* <p>Instances of this abstract type expose read-oriented counters (hits, misses, false positives)
* and write counters as observed by a particular store. Implementations typically back these values
* with thread-safe counters updated by the store’s I/O path and may compute derived rates from the
* exposed primitives. The contract is deliberately minimal so it can model both in-memory caches
* exposed primitives. The contract is deliberately minimal, so it can model both in-memory caches
* and persistent stores with different eviction and validation strategies.
*
* <p>The methods are intended for metrics dashboards, admin endpoints, and diagnostics. Values
Expand All @@ -18,10 +18,9 @@
* <ul>
* <li>Use the primitive counters for precise alerting and long-term trends.
* <li>Prefer rates for visualizing traffic patterns; calibrate for your deployment scale.
* <li>Handle unavailability explicitly (for example, at startup or with empty histories).
* <li>Handle unavailability explicitly (for example, at a startup or with empty histories).
* </ul>
*
* @see network.crypta.node.stats.DataStoreStats
* @see network.crypta.node.stats.StatsNotAvailableException
*/
public abstract class StoreAccessStats {
Expand Down Expand Up @@ -62,8 +61,8 @@ protected StoreAccessStats() {}
* Returns the number of false positives detected during lookups.
*
* <p>False positives generally occur when a preliminary test (such as a probabilistic filter)
* indicates presence, yet the object is not actually retrievable. This counter helps assess
* filter tuning and its impact on unnecessary follow-on work.
* indicates presence, yet the object is not retrievable. This counter helps assess filter tuning
* and its impact on unnecessary follow-on work.
*
* @return non-negative count of false positives observed so far; monotonically non-decreasing per
* process unless counters are reset by the implementation.
Expand All @@ -73,8 +72,8 @@ protected StoreAccessStats() {}
/**
* Returns the number of write operations issued to the store.
*
* <p>Depending on the store, a write may represent an insert, update, or a completed fill after a
* miss. The counter reflects successfully issued writes; failures may or may not be included
* <p>Depending on the store, a writing may represent an insert, update, or a completed fill after
* a miss. The counter reflects successfully issued writes; failures may or may not be included
* based on implementation policy.
*
* @return non-negative count of writes observed so far; monotonically non-decreasing per process
Expand Down Expand Up @@ -111,8 +110,8 @@ public long successfulReads() {
* Returns the read success rate as a percentage of total reads.
*
* <p>Calculated as {@code (100.0 * hits() / readRequests())}. When no reads have been observed
* yet, the rate is undefined and this method signals unavailability rather than returning a value
* that could be misinterpreted.
* yet, the rate is undefined, and this method signals unavailability rather than returning a
* value that could be misinterpreted.
*
* @return a percentage in the range {@code [0.0, 100.0]} when at least one read has been
* observed. The exact rounding behavior follows IEEE-754 double arithmetic.
Expand Down Expand Up @@ -140,7 +139,7 @@ public double accessRate(long nodeUptimeSeconds) {
}

/**
* Returns the average write rate per second for the node uptime period.
* Returns the average writing rate per second for the node uptime period.
*
* <p>Computed as {@code writes() / nodeUptimeSeconds}. As with {@link #accessRate(long)}, callers
* should provide a strictly positive uptime to avoid undefined ratios at startup.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package network.crypta.store.alerts;

/**
* Receives dynamic store-maintenance alert sources published by store implementations.
*
* <p>This interface is the narrow boundary between the leaf-owned store layer and the root-owned
* runtime alert system. Stores do not format text, localize strings, or build UI fragments.
* Instead, they register a live {@link StoreMaintenanceAlertSource} and allow the runtime layer to
* decide whether that source becomes a user alert, log entry, diagnostics panel, or no visible
* output at all.
*
* <p>The contract is intentionally small so the store layer can remain reusable and testable. A
* sink implementation may keep the source for repeated polling, transform it into another alert
* representation, or ignore it completely when the current runtime does not expose maintenance
* alerts.
*
* @see StoreMaintenanceAlertSource
*/
public interface StoreAlertSink {
/**
* Sink that silently drops all registrations.
*
* <p>Use this when a caller wants to avoid null checks but has no alert destination for store
* maintenance progress.
*/
StoreAlertSink NO_OP = _ -> {};

/**
* Registers a store-maintenance alert source with this sink.
*
* <p>The source is expected to remain dynamic after registration. Implementations may poll it
* repeatedly, snapshot it immediately, or decide not to surface it. Callers should typically
* register long-lived sources once rather than creating new source objects for every progress
* update.
*
* @param alert live source describing a maintenance operation and its current progress; sink
* implementations may ignore it when the runtime does not expose alerts
*/
void register(StoreMaintenanceAlertSource alert);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package network.crypta.store.alerts;

/**
* Lists the maintenance progress categories that stores can expose through the alert SPI.
*
* <p>Runtime adapters use these values to pick localization keys and presentation details while the
* store layer remains free of user-interface code. The enum is intentionally small because the
* current boundary only needs to describe long-running resize and rebuild work.
*/
public enum StoreMaintenanceAlertKind {
/**
* Progress for a store resize operation that changes the effective capacity of the datastore.
*
* <p>Typical runtimes present this as an operator-visible task because resizing can run for an
* extended period and may temporarily reduce performance.
*/
RESIZE_PROGRESS,

/**
* Progress for a store rebuild or maintenance pass over existing store data.
*
* <p>This covers both legacy slot-filter rebuilds after an unclean shutdown and rebuilds that
* convert data into a newer maintenance format.
*/
REBUILD_PROGRESS
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package network.crypta.store.alerts;

/**
* Provides live, store-facing data for a maintenance progress alert.
*
* <p>Implementations expose a small, polling-friendly view of an in-flight store operation such as
* a resize or rebuild. The values returned from this interface are intentionally presentation-free:
* they identify the affected store, describe the kind of work in progress, and report progress
* counters that the runtime can localize and render however it needs. This keeps formatting, HTML
* generation, and runtime policy outside the store layer.
*
* <p>Callers should treat instances as dynamic and read-mostly. Repeated invocations may return
* different values as maintenance proceeds, and {@link #isValid()} may switch from {@code true} to
* {@code false} when the operation completes or is canceled.
*
* @see StoreAlertSink
* @see StoreMaintenanceAlertKind
*/
public interface StoreMaintenanceAlertSource {
/**
* Returns a stable anchor string for this maintenance alert.
*
* <p>The anchor is used by runtime adapters as a durable identifier for deduplication, fragment
* links, or UI element IDs. It should remain stable for the lifetime of the underlying
* maintenance task and avoid characters that would be awkward in URLs or HTML identifiers.
*
* @return a short, stable identifier for the alert source that remains constant while the
* maintenance operation is active
*/
String anchor();

/**
* Returns the human-readable name of the affected store.
*
* <p>This value is intended for interpolation into localized runtime messages. It should be
* concise and recognizable to operators, for example, the configured datastore name or cache
* label.
*
* @return store name suitable for operator-facing alert text and diagnostics
*/
String storeName();

/**
* Returns the kind of maintenance task currently represented by this source.
*
* <p>Runtime adapters use this value to select the appropriate localization keys, severity, and
* surrounding presentation. Implementations should return the same value throughout one logical
* maintenance task.
*
* @return enum value describing whether the alert represents resize progress, rebuild progress,
* or another future maintenance category
*/
StoreMaintenanceAlertKind kind();

/**
* Returns the amount of maintenance work completed so far.
*
* <p>The unit must match {@link #total()}. Implementations typically report processed slots,
* entries, or similar work units. The value should be non-negative and usually monotonic while
* the task is valid.
*
* @return completed work units for the current maintenance task, in the same units as {@link
* #total()}
*/
long processed();

/**
* Returns the total amount of work expected for the maintenance task.
*
* <p>This provides the denominator for progress displays. Implementations should keep the unit
* consistent with {@link #processed()}. The value may be zero when the total is unknown or when a
* task has not started computing progress yet.
*
* @return total expected work units for the current task, using the same unit system as {@link
* #processed()}
*/
long total();

/**
* Reports whether the task is rebuilding into the newer slot-filter format.
*
* <p>This flag lets the runtime choose between the legacy rebuild wording and the newer
* conversion wording without forcing the store to produce preformatted strings. Callers should
* interpret the flag only for rebuild-style alerts.
*
* @return {@code true} when the rebuild path is converting to the new slot-filter format; {@code
* false} for legacy rebuilds and non-rebuild tasks
*/
boolean newSlotFilter();

/**
* Reports whether this alert source should still be shown.
*
* <p>Once this method returns {@code false}, runtime adapters should treat the maintenance alert
* as finished or obsolete and stop presenting it. Implementations may return {@code false} when
* the task completes, is canceled, or is replaced by a new source.
*
* @return {@code true} while the source represents an active maintenance condition; {@code false}
* when the alert should be considered stale or complete
*/
boolean isValid();
}
3 changes: 3 additions & 0 deletions foundation-support/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ plugins {
version = rootProject.version

dependencies {
implementation(project(":foundation-fs"))
implementation(libs.slf4jApi)
implementation(project(":thirdparty-legacy"))
implementation(libs.commonsCompress)
implementation(libs.jna)
implementation(libs.jnaPlatform)
implementation(files(rootProject.file("libs/wrapper.jar")))
compileOnly(libs.jetbrainsAnnotations)
}
12 changes: 12 additions & 0 deletions foundation-support/gradle/owned-output-patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Keep this list limited to the stable generic support subset extracted into :foundation-support.

network/crypta/node/FSParseException*
network/crypta/node/FastRunnable*
network/crypta/node/SemiOrderedShutdownHook*
network/crypta/io/WritableToDataOutputStream*
network/crypta/support/api/Bucket*
network/crypta/support/api/BucketFactory*
Expand All @@ -11,12 +13,18 @@ network/crypta/support/api/RandomAccessBucket*
network/crypta/support/api/RandomAccessBuffer*
network/crypta/support/api/ResumeContext*
network/crypta/support/Base64*
network/crypta/support/DoublyLinkedList*
network/crypta/support/DoublyLinkedListImpl*
network/crypta/support/ByteArrayWrapper*
network/crypta/support/Fields*
network/crypta/support/HTMLEncoder*
network/crypta/support/HTMLEntities*
network/crypta/support/HTMLNode*
network/crypta/support/HexUtil*
network/crypta/support/IllegalBase64Exception*
network/crypta/support/LRUMap*
network/crypta/support/LightweightException*
network/crypta/support/PromiscuousItemException*
network/crypta/support/PriorityAwareExecutor*
network/crypta/support/Loader*
network/crypta/support/SimpleReadOnlyArrayBucket*
Expand All @@ -27,6 +35,8 @@ network/crypta/support/TimeUtil*
network/crypta/support/URLDecoder*
network/crypta/support/URLEncodedFormatException*
network/crypta/support/URLEncoder*
network/crypta/support/VirginItemException*
network/crypta/support/WrapperKeepalive*
network/crypta/support/XMLCharacterClasses*
network/crypta/support/io/AtomicFileMoves*
network/crypta/support/io/ArrayBucket*
Expand All @@ -43,6 +53,7 @@ network/crypta/support/io/DiskSpaceChecker*
network/crypta/support/io/HeaderStreams*
network/crypta/support/io/IOUtils*
network/crypta/support/io/InetAddressComparator*
network/crypta/support/io/Fallocate*
network/crypta/support/io/FilenameGenerator*
network/crypta/support/io/FilenameSanitizer*
network/crypta/support/io/InsufficientDiskSpaceException*
Expand All @@ -58,6 +69,7 @@ network/crypta/support/io/NullRandomAccessBuffer*
network/crypta/support/io/NullWriter*
network/crypta/support/io/PersistentFileTracker*
network/crypta/support/io/PersistentFilenameGenerator*
network/crypta/support/io/NativeThread*
network/crypta/support/io/RAFInputStream*
network/crypta/support/io/RandomAccessFileOutputStream*
network/crypta/support/io/ReadOnlyFileSliceBucket*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package network.crypta.node;

/**
* Marker interface for short, non-blocking tasks that are safe to execute inline on
* latency-sensitive threads.
*
* <p>Schedulers in this codebase, including the packet sender and ticker implementations in the
* runtime layer, may check whether a task implements {@code FastRunnable}. When it does, they can
* invoke {@link #run()} directly on the calling thread to minimize scheduling overhead and wake-up
* latency. Tasks that do not implement this interface are typically offloaded to an executor.
*
* <p>Implementations are expected to keep {@link #run()} extremely short and to avoid blocking
* operations such as sleep, I/O, lock contention, or long computations. A slow "fast" task can
* stall a networking or ticker thread and reduce overall throughput. Callers may invoke these tasks
* on shared infrastructure threads, so implementations should not rely on thread-local state or
* thread-affinity behavior. Unchecked exceptions are handled by the calling scheduler, but
* implementations should still avoid throwing when practical.
*
* <p>Memory visibility follows the usual {@link Runnable} contract. This marker does not add any
* extra happens-before guarantees beyond those established by the scheduler that invokes {@link
* #run()}.
*/
public interface FastRunnable extends Runnable {}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
* <p>On shutdown, this hook starts all early jobs concurrently and joins each with a fixed
* per-thread timeout. It then starts late jobs and joins them with the same timeout. If an
* interruption occurs while joining, it is remembered and the interrupted status is restored after
* both join loops complete. This allows the remaining joins to proceed while still propagating the
* interrupt to callers.
* both join loops are complete. This allows the remaining joins to proceed while still propagating
* the interrupt to callers.
*
* <p>Thread safety: registration methods are synchronized. Snapshots of job lists are taken at
* {@link #run()} time to avoid holding locks during joins. Callers should register jobs before
* {@link #run()} time to avoid holding locks during joins. Callers should register jobs before the
* shutdown begins.
*
* <p>Usage: obtain the singleton via {@link #get()} and register unstarted threads with {@link
* <p>Usage: get the singleton via {@link #get()} and register unstarted threads with {@link
* #addEarlyJob(Thread)} or {@link #addLateJob(Thread)}. The hook calls {@link Thread#start()}.
*/
@SuppressWarnings({"java:S6548", "java:S2142"})
Expand Down Expand Up @@ -91,7 +91,7 @@ public void run() {
try {
r.join(TIMEOUT);
} catch (InterruptedException _) {
// Remember interruption and continue joining remaining threads.
// Remember the interruption and continue joining remaining threads.
wasInterrupted = true;
}
}
Expand All @@ -108,14 +108,14 @@ public void run() {
try {
r.join(TIMEOUT);
} catch (InterruptedException _) {
// Remember interruption and continue joining remaining threads.
// Remember the interruption and continue joining remaining threads.
wasInterrupted = true;
}
}

if (wasInterrupted) {
// Restore the interrupted status after all joins so callers can observe it
// without causing subsequent joins in this method to fail immediately.
// without causing later joins in this method to fail immediately.
Thread.currentThread().interrupt();
}
}
Expand Down
Loading
Loading