Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classA profile file considered for deletion, with the age that decides its order.private static classFilter selecting the profile files.Field Summary
Modifier and TypeFieldDescriptionprivate final RouterContextThe router context.private final LogLogger for the profile storage.Peers whose profile was loaded while the netdb held no RouterInfo, collected duringreadProfiles().private final FileDirectory holding the profile files.private intLast known number of profile files on disk, from the most recent load or purge.private HashOur router hash.private static final StringAlphabet of the base64 hash in the file names.static final StringDefault peer profile directory name, relative to the router directory.private static final StringPrefix of the profile subdirectory names.private static final StringComment rule line of the profile file.private static final intProfiles kept on disk.private static final intShortest valid profile file name.private static final StringThe platform line separator.private static final StringFilename suffix of the old serialized profile files.private static final StringFilename prefix of the profile files.static final StringConfig property naming the base directory that peer profiles are stored under.private static final long[]Rate stat periods for the profile statistics.(package private) static final longAge beyond which a peer that is also absent from the network database is treated as gone, making its profile file deletable at any store size.private static final StringProfiles that loaded carrying the persisted low-latency flag.private static final StringProfiles whose stored first-hop RTT had aged past the validity window.private static final StringProfiles that loaded with a first-hop RTT still inside its validity window.private static final StringStat name for the number of stored profiles.private static final StringFilename suffix of the compressed profile files.private static final StringFilename suffix of the uncompressed profile files.Constructor Summary
ConstructorsConstructorDescriptionConstruct a helper that reads and writes peer profiles under the router directory.Method Summary
Modifier and TypeMethodDescriptionprivate static voidadd(StringBuilder buf, boolean addComments, String name, long val, String description) Write a profile property, with a comment if requested.private static voidaddDate(StringBuilder buf, boolean addComments, String name, long val, String description) Write a date property, with a comment if requested.intdeleteOldProfiles(long age) Delete profile files with timestamps older than 'age' ago.private voidFirst heard about wasn't always set correctly before, set it to the minimum of all recorded timestamps.private static final floatgetFloat(Properties props, String key) Reads a float property with a default of zero.private HashExtracts the router hash from a profile file name.(package private) static longgetLong(Properties props, String key) Parse a long value from the properties, or 0 if missing or invalid.intLast known number of profile files on disk, from the most recent load, stale-profile cleanup, or purge.(package private) static booleanisGenuinelyStale(boolean absentFromNetDb, long lastActivity, long now, long staleAge) Is a profile file genuinely stale, and therefore deletable whatever the store size?private voidloadProps(Properties props, File file) Loads one profile file's properties.private voidMigrate from one-level to two-level directory structure.private static longnewestOf(long a, long b, long c) Newest of three timestamps, treating absent (0) as oldest.private FilepickFile(PeerProfile profile) Chooses the profile file for a peer.(package private) static voidpurgeCapacityBonus(Properties props) Drop the capacity-bonus keys from a loaded profile's properties.voidpurgeExcessProfiles(Set<Hash> keepPeers, int retentionFloor) Delete profile files that are no longer worth keeping.readProfile(File file, long cutoff) Read and parse a single stored profile.Load all existing profiles from the profile directory.Picks the profile files to load, newest first.(package private) voidsetMissingRouterInfoSink(Set<Hash> missingRouterInfo) Supply the set to collect peers-without-RouterInfo into.private voidsetStoredProfileCount(int count) Record the number of profile files on disk and publish it for graphing.voidStore the local router identity hash for filtering out the router's own profile.(package private) static intsurplusToDelete(int storedFiles, int retentionFloor, int surplusAvailable) How many surplus (non-stale) profiles to delete to bring the store back to the retention floor.booleanwriteProfile(PeerProfile profile) Write the data from the profile to the file.voidwriteProfile(PeerProfile profile, OutputStream out) Write the data from the profile to the stream includes comments.voidwriteProfile(PeerProfile profile, OutputStream out, boolean addComments) Write the data from the profile to the stream.
Field Details
_log
Logger for the profile storage._context
The router context.STALE_PROFILE_AGE_MS
static final long STALE_PROFILE_AGE_MSAge beyond which a peer that is also absent from the network database is treated as gone, making its profile file deletable at any store size.Seven days. The previous logic used a 24-hour activity threshold and separately deleted K/L/M/Unknown bandwidth peers regardless of age, so a peer merely quiet overnight could lose its learned history. Those peers are no longer written at all; this threshold now governs only what is left on disk from before that. A peer that has been out of the network for a week will not be selected by a RouterInfo that has since expired anyway.
- See Also:
PROP_PEER_PROFILE_DIR
Config property naming the base directory that peer profiles are stored under.- See Also:
DEFAULT_PEER_PROFILE_DIR
Default peer profile directory name, relative to the router directory.- See Also:
NL
The platform line separator.HR
PREFIX
Filename prefix of the profile files.- See Also:
SUFFIX
Filename suffix of the compressed profile files.- See Also:
UNCOMPRESSED_SUFFIX
Filename suffix of the uncompressed profile files.- See Also:
OLD_SUFFIX
Filename suffix of the old serialized profile files.- See Also:
MIN_NAME_LENGTH
private static final int MIN_NAME_LENGTHShortest valid profile file name.DIR_PREFIX
Prefix of the profile subdirectory names.- See Also:
B64
Alphabet of the base64 hash in the file names.- See Also:
LIMIT_PROFILES
private static final int LIMIT_PROFILESProfiles kept on disk._profileDir
Directory holding the profile files._us
Our router hash._storedProfileCount
private volatile int _storedProfileCountLast known number of profile files on disk, from the most recent load or purge.STAT_STORED_PROFILES
Stat name for the number of stored profiles.- See Also:
STAT_LOADED_WITH_RTT
Profiles that loaded with a first-hop RTT still inside its validity window. A non-zero value here is the confirmation that a transport is actually supplying latency: without one, every profile would fall intoSTAT_LOADED_RTT_EXPIREDor neither, and the fast tier would be seeded from persisted flags alone.- See Also:
STAT_LOADED_RTT_EXPIRED
Profiles whose stored first-hop RTT had aged past the validity window.- See Also:
STAT_LOADED_LOW_LATENCY
Profiles that loaded carrying the persisted low-latency flag.- See Also:
RATES
private static final long[] RATESRate stat periods for the profile statistics._missingRouterInfo
Peers whose profile was loaded while the netdb held no RouterInfo, collected duringreadProfiles().These profiles are kept on disk but inert until the RouterInfo is fetched again, so the caller needs the list to go and request it. Empty when no collection has been supplied.
Constructor Details
ProfilePersistenceHelper
Construct a helper that reads and writes peer profiles under the router directory.- Parameters:
ctx- the router context, whose router directory holds the profile files
Method Details
setStoredProfileCount
private void setStoredProfileCount(int count) Record the number of profile files on disk and publish it for graphing.Every path that recomputes the count routes through here rather than assigning the field directly, so the graphed gauge cannot drift from the value the store actually holds.
- Parameters:
count- number of profile files currently on disk
getStoredProfileCount
public int getStoredProfileCount()Last known number of profile files on disk, from the most recent load, stale-profile cleanup, or purge.- Returns:
- the stored profile count, 0 if the store has never been scanned
setUs
Store the local router identity hash for filtering out the router's own profile.- Parameters:
routerIdentHash- this router's identity hash, or null to stop filtering it out
writeProfile
Write the data from the profile to the file.A rare, benign failure mode: a concurrent purge (
purgeExcessProfiles(Set, int)) or expiry sweep can remove the profile, or its shard directory (peerProfiles/pX), betweenpickFile(PeerProfile)and the open. When the shard directory vanished it is re-created and the write retried once so the store stays self-healing; anything else is a race or a genuine store problem and is worth a WARN without a stacktrace, not an ERROR.- Parameters:
profile- the profile to serialize- Returns:
- true if the profile was written, false if it could not be stored
writeProfile
Write the data from the profile to the stream includes comments.- Parameters:
profile- the profile to serializeout- the stream to write the serialized profile to, not closed by this method- Throws:
IOException- if the stream cannot be written
writeProfile
public void writeProfile(PeerProfile profile, OutputStream out, boolean addComments) throws IOException Write the data from the profile to the stream.- Parameters:
profile- the profile to serializeout- the stream to write the serialized profile to, not closed by this methodaddComments- add comment lines to the output- Throws:
IOException- if the stream cannot be written
addDate
private static void addDate(StringBuilder buf, boolean addComments, String name, long val, String description) Write a date property, with a comment if requested.- Parameters:
buf- the builder to append the line toaddComments- true to append the comment line, false the property linename- the property name to writeval- the timestamp in ms, 0 or less meaning neverdescription- comment text, the rendered date is appended to it
add
private static void add(StringBuilder buf, boolean addComments, String name, long val, String description) Write a profile property, with a comment if requested.- Parameters:
buf- the builder to append the line toaddComments- true to append the comment line, false the property linename- the property name to writeval- the numeric value to writedescription- comment text for the property
readProfiles
Load all existing profiles from the profile directory.- Returns:
- the profiles read, most recently modified first, capped at the store limit
selectFiles
migrate
Migrate from one-level to two-level directory structure.- Parameters:
files- the flat profile files to move into the two-level structure
deleteOldProfiles
public int deleteOldProfiles(long age) Delete profile files with timestamps older than 'age' ago.- Parameters:
age- how far back in milliseconds a profile must predate to be deleted- Returns:
- the number of profile files removed
readProfile
Read and parse a single stored profile.- Parameters:
file- the profile file to readcutoff- delete and return null if older than this (absolute time)- Returns:
- the parsed profile, or null if the file was deleted as stale or malformed
fixupFirstHeardAbout
First heard about wasn't always set correctly before, set it to the minimum of all recorded timestamps.- Parameters:
p- the profile whose firstHeardAbout is corrected in place
purgeCapacityBonus
Drop the capacity-bonus keys from a loaded profile's properties. A capacity bonus is a live, manual nudge set on the configpeers page; it must not survive a restart, and old profile files could carry one with no expiry timestamp, which the 4-hour decay would then treat as valid forever. Removing the keys here also clears them from disk on the next save.- Parameters:
props- the parsed profile properties, modified in place
getLong
Parse a long value from the properties, or 0 if missing or invalid.- Parameters:
props- the parsed profile propertieskey- the property name to read- Returns:
- the long value or 0
getFloat
Reads a float property with a default of zero.- Parameters:
props- the properties readkey- the property name- Returns:
- the value, zero if unparseable
loadProps
Loads one profile file's properties.- Parameters:
props- the properties to fillfile- the file to read- Throws:
IOException- if the file cannot be read
setMissingRouterInfoSink
Supply the set to collect peers-without-RouterInfo into.- Parameters:
missingRouterInfo- the set to fill duringreadProfiles(), or null to collect nothing
getHash
pickFile
Chooses the profile file for a peer.- Parameters:
profile- the profile to name- Returns:
- the file to use
isGenuinelyStale
static boolean isGenuinelyStale(boolean absentFromNetDb, long lastActivity, long now, long staleAge) Is a profile file genuinely stale, and therefore deletable whatever the store size?Both conditions are required. Absence from the network database alone means the RouterInfo expired, which happens routinely while a peer is offline for an hour; inactivity alone means the peer has not been heard from recently, which is equally routine. Only the conjunction identifies a profile whose peer has been gone long enough that its learned history is worth nothing.
Pure decision, safe for unit tests.
- Parameters:
absentFromNetDb- true if no usable RouterInfo is held for the peerlastActivity- newest of last-sent-successfully, last-heard-from and last-heard-about, or 0 if the profile records nonenow- current time in msstaleAge- age beyond which an absent peer is treated as gone, in ms- Returns:
- true if the file may be deleted regardless of store size
surplusToDelete
static int surplusToDelete(int storedFiles, int retentionFloor, int surplusAvailable) How many surplus (non-stale) profiles to delete to bring the store back to the retention floor.Stale profiles are deleted independently of this, so this counts only the additional trimming that the store being over its floor justifies. It is zero below the floor, which is what makes "never delete below the floor unless genuinely stale" hold regardless of how many profiles are active.
Pure decision, safe for unit tests.
- Parameters:
storedFiles- profile files currently on diskretentionFloor- file count to keep, exclusive of stale profilessurplusAvailable- surplus profiles not already counted as stale- Returns:
- number of surplus files to delete, never negative and never more than
surplusAvailable
purgeExcessProfiles
Delete profile files that are no longer worth keeping.Two rules, in this order:
- a profile that is genuinely stale is deleted at any store size, oldest first;
- a profile that is merely surplus is deleted only while the store is above
retentionFloor, least-recently-active first.
Low-bandwidth peers are excluded where it belongs, on the write path in
PeerManager.storeProfile(), so no K/L/M/Unknown profile is created in the first place. This method used to remove them instead, ahead of any age check, which deleted the file of a peer heard from minutes earlier and only by accident got the right answer: files already on disk from before that check existed still age out here, through the stale bucket or the surplus trim.Ordering uses the profile's own recorded activity rather than the file's modification time, because profiles are rewritten whenever they are stored and so carry a fresh mtime even for a peer long gone.
- Parameters:
keepPeers- peers whose files must be preserved, may be nullretentionFloor- file count to keep before trimming surplus
newestOf
private static long newestOf(long a, long b, long c) Newest of three timestamps, treating absent (0) as oldest.- Parameters:
a- first timestamp, 0 if unknownb- second timestamp, 0 if unknownc- third timestamp, 0 if unknown- Returns:
- the largest non-zero value, or 0 if all are 0