YAACC - UPNP Client and Server
Loading...
Searching...
No Matches
de.yaacc.share.ShareRegistry Class Reference

In-memory registry of the active shares served by the temporary media proxy. More...

Collaboration diagram for de.yaacc.share.ShareRegistry:
Collaboration graph

Classes

class  Entry
 One share.
 
enum  Kind
 What the target of an entry is. More...
 

Public Member Functions

 ShareRegistry (LongSupplier nowMillis, Consumer< byte[]> randomBytes, int maxActive)
 
 ShareRegistry (LongSupplier nowMillis, Consumer< byte[]> randomBytes)
 Same with DEFAULT_MAX_ACTIVE.
 
String register (Entry entry)
 Registers an entry.
 
String registerOrEvict (Entry entry)
 The one way the glue puts an entry into the registry: if the registry is full, the entry that was released the longest ago (a leftover of an ended playback) is evicted (evictOldestReleased()) and the registration is tried ONCE more.
 
Entry lookup (String key)
 
boolean markActive (String key)
 Cancels a pending release (a player started again, a renderer is still fetching).
 
void release (String key)
 Starts the grace period (the player ended).
 
boolean remove (String key)
 Removes the entry now and closes its target (once).
 
boolean evictOldestReleased ()
 Makes room for a new share: removes and closes the entry that was released the longest ago and is still in its grace period (a leftover of an ended playback).
 
boolean hasRoom ()
 A cheap look before a file is opened: whether registerOrEvict would find a slot (a free one, an expired one or a released one that can be evicted).
 
int expire ()
 Removes and closes every entry that has expired.
 
void removeAll ()
 Removes and closes every entry (service stop).
 
int size ()
 

Static Public Member Functions

static ShareRegistry createDefault ()
 A registry on the monotonic system clock and a SecureRandom.
 
static boolean isWellFormedKey (String key)
 Format check for the key from a request path, used by the proxy handler BEFORE the lookup (no registry state needed): exactly {@value KEY_TEXT_LENGTH} characters, each one of A-Z a-z 0-9 - _ (the unpadded base64url form of KEY_BYTES bytes).
 

Static Public Attributes

static final int DEFAULT_MAX_ACTIVE = 8
 How many active entries the default registry holds.
 
static final int KEY_BYTES = 16
 Number of random bytes behind a key (128 bit).
 
static final int KEY_TEXT_LENGTH = 22
 Length of a key in characters: KEY_BYTES bytes as unpadded base64url.
 

Detailed Description

In-memory registry of the active shares served by the temporary media proxy.

Plain Java with an injectable clock and random source so it can be unit tested on the JVM.

Every entry gets a random key: 16 bytes from the random source, encoded as unpadded base64url (22 characters). The key depends on nothing but the random bytes (not on the target), is never handed out twice while the registry lives (retired keys are remembered for a bounded window of recent keys, which is plenty for a 128-bit random source and keeps the memory bounded), and is the only way to reach the entry. Nothing is persisted.

Lifetime of an entry: it expires absoluteMaxMillis after registration, or, once release(String) was called, idleGraceMillis after the first release, whichever comes first (markActive(String) cancels a pending release). An expired entry is never returned; it is removed and its target closed when it is noticed (by lookup, register, size or expire()). A target that implements AutoCloseable is closed exactly once, whichever way the entry goes (remove, expiry, removeAll()); an exception from close() is swallowed. At most maxActive entries are held; register returns null when none is free.

All methods are thread safe. No method throws for a null, empty or garbage key.

Constructor & Destructor Documentation

◆ ShareRegistry()

de.yaacc.share.ShareRegistry.ShareRegistry ( LongSupplier nowMillis,
Consumer< byte[]> randomBytes,
int maxActive )
Parameters
nowMillismonotonic clock in milliseconds, not null
randomBytesfills the given array with random bytes (e.g.
new SecureRandom()::nextBytes
), not null; must be thread safe or is only called under the registry's lock
maxActive> 0
Exceptions
IllegalArgumentExceptionfor a null argument or a non-positive maximum

Referenced by de.yaacc.share.ShareRegistry.createDefault().

Here is the caller graph for this function:

Member Function Documentation

◆ evictOldestReleased()

boolean de.yaacc.share.ShareRegistry.evictOldestReleased ( )

Makes room for a new share: removes and closes the entry that was released the longest ago and is still in its grace period (a leftover of an ended playback).

Entries that were never released are not touched, so a running playback is never cut. Expired entries are swept as well.

Returns
true if an entry was evicted (a slot is free, apart from a concurrent register); false if there is no released entry

Referenced by de.yaacc.share.ShareRegistry.registerOrEvict().

Here is the caller graph for this function:

◆ expire()

int de.yaacc.share.ShareRegistry.expire ( )

Removes and closes every entry that has expired.

Returns
how many were removed

◆ hasRoom()

boolean de.yaacc.share.ShareRegistry.hasRoom ( )

A cheap look before a file is opened: whether registerOrEvict would find a slot (a free one, an expired one or a released one that can be evicted).

Nothing is changed.

◆ isWellFormedKey()

static boolean de.yaacc.share.ShareRegistry.isWellFormedKey ( String key)
static

Format check for the key from a request path, used by the proxy handler BEFORE the lookup (no registry state needed): exactly {@value KEY_TEXT_LENGTH} characters, each one of A-Z a-z 0-9 - _ (the unpadded base64url form of KEY_BYTES bytes).

ASCII only: no padding =, no + / . %, no whitespace, no unicode letters or digits. Nothing is trimmed or decoded.

Returns
false for null, empty, any other length and any other character

Referenced by de.yaacc.share.ShareKeyTracker< P >.keyOfProxyPath(), de.yaacc.share.ShareRegistry.lookup(), de.yaacc.share.ShareRegistry.markActive(), de.yaacc.share.ShareKeyTracker< P >.refresh(), de.yaacc.share.ShareRegistry.release(), de.yaacc.share.ShareRegistry.remove(), de.yaacc.share.ShareConcurrencyLimiter.tryAcquire(), and de.yaacc.upnp.server.http.YaaccUpnpServerContentHttpHandler.updateRendererPosition().

Here is the caller graph for this function:

◆ lookup()

Entry de.yaacc.share.ShareRegistry.lookup ( String key)
Returns
the live entry for the key, or null for an unknown, garbage, expired or released-and-grace-over key (an expired entry is removed and closed on the way)
Here is the call graph for this function:

◆ markActive()

boolean de.yaacc.share.ShareRegistry.markActive ( String key)

Cancels a pending release (a player started again, a renderer is still fetching).

Does not extend the absolute maximum.

Returns
true if the key names a live entry
Here is the call graph for this function:

◆ register()

String de.yaacc.share.ShareRegistry.register ( Entry entry)

Registers an entry.

If no slot is free, expired entries are swept first, so they never block a free slot. Entries that were released but are still in their grace period keep their slot; a caller that wants such an entry to make room calls evictOldestReleased() and retries.

Returns
the new key, or null if maxActive entries are active or no unused key could be drawn (a broken random source repeating itself); in both cases nothing is stored and the caller keeps ownership of the target (the registry does not close it)
Exceptions
IllegalArgumentExceptionif the entry is null

Referenced by de.yaacc.share.ShareRegistry.registerOrEvict().

Here is the caller graph for this function:

◆ registerOrEvict()

String de.yaacc.share.ShareRegistry.registerOrEvict ( Entry entry)

The one way the glue puts an entry into the registry: if the registry is full, the entry that was released the longest ago (a leftover of an ended playback) is evicted (evictOldestReleased()) and the registration is tried ONCE more.

The registry does not close the target of an entry it refused: when this returns null the caller still owns the target and must close it.

Returns
the new key, or null if there was no room even after an eviction (the caller keeps ownership of the target)
Here is the call graph for this function:

◆ release()

void de.yaacc.share.ShareRegistry.release ( String key)

Starts the grace period (the player ended).

The first release counts; repeated releases do not restart the grace period. Unknown keys are ignored.

Here is the call graph for this function:

◆ remove()

boolean de.yaacc.share.ShareRegistry.remove ( String key)

Removes the entry now and closes its target (once).

Returns
true if an entry was removed

Referenced by de.yaacc.upnp.UpnpClient.createPlayableItem(), and de.yaacc.upnp.UpnpClient.discardShareOf().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ size()

int de.yaacc.share.ShareRegistry.size ( )
Returns
the number of live entries (expired ones are swept first)

Referenced by de.yaacc.share.ShareRegistry.size().

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following file: