Skip to content

Commit 6ce7f3b

Browse files
committed
javadoc + refactor
1 parent b76e205 commit 6ce7f3b

60 files changed

Lines changed: 940 additions & 360 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/java/net/staticstudios/data/data/value/redis/CachedValue.java renamed to src/main/java/net/staticstudios/data/CachedValue.java

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
1-
package net.staticstudios.data.data.value.redis;
1+
package net.staticstudios.data;
22

3-
import net.staticstudios.data.*;
43
import net.staticstudios.data.data.DataHolder;
5-
import net.staticstudios.data.data.UniqueData;
4+
import net.staticstudios.data.data.value.InitialCachedValue;
65
import net.staticstudios.data.data.value.Value;
76
import net.staticstudios.data.impl.CachedValueManager;
87
import net.staticstudios.data.key.RedisKey;
98
import net.staticstudios.data.primative.Primitive;
109
import net.staticstudios.data.primative.Primitives;
10+
import net.staticstudios.data.util.DataDoesNotExistException;
11+
import net.staticstudios.data.util.DeletionStrategy;
12+
import net.staticstudios.data.util.ValueUpdate;
13+
import net.staticstudios.data.util.ValueUpdateHandler;
1114
import net.staticstudios.utils.ThreadUtils;
1215
import org.jetbrains.annotations.Blocking;
1316
import org.jetbrains.annotations.NotNull;
17+
import org.jetbrains.annotations.Nullable;
1418
import redis.clients.jedis.Jedis;
1519

1620
import java.time.Instant;
1721
import java.util.List;
1822
import java.util.function.Supplier;
1923

24+
/**
25+
* Represents a value that lives in Redis.
26+
* Data stored in {@link CachedValue} objects should be considered volatile and may be deleted at any time.
27+
*
28+
* @param <T> the type of data stored in this value
29+
*/
2030
public class CachedValue<T> implements Value<T> {
2131
private final String identifyingKey;
2232
private final Class<T> dataType;
@@ -37,22 +47,51 @@ private CachedValue(String key, Class<T> dataType, DataHolder holder, DataManage
3747
this.dataManager = dataManager;
3848
}
3949

50+
/**
51+
* Create a new {@link CachedValue} object.
52+
*
53+
* @param holder the holder of this value
54+
* @param dataType the type of data stored in this value
55+
* @param key the identifying key for this value (note that this is only part of what is used to construct the Redis key, see {@link RedisKey#toString()})
56+
* @param <T> the type of data stored in this value
57+
* @return the new {@link CachedValue} object
58+
*/
4059
public static <T> CachedValue<T> of(UniqueData holder, Class<T> dataType, String key) {
4160
CachedValue<T> cv = new CachedValue<>(key, dataType, holder, holder.getDataManager());
4261
cv.deletionStrategy = DeletionStrategy.CASCADE;
4362
return cv;
4463
}
4564

46-
public InitialCachedValue initial(T value) {
65+
/**
66+
* Set the initial value for this object
67+
*
68+
* @param value the initial value
69+
* @return the initial value object
70+
*/
71+
public InitialCachedValue initial(@Nullable T value) {
4772
return new InitialCachedValue(this, value);
4873
}
4974

75+
/**
76+
* Add an update handler to this value.
77+
* Note that update handlers are run asynchronously.
78+
*
79+
* @param updateHandler the update handler
80+
* @return this
81+
*/
5082
@SuppressWarnings("unchecked")
5183
public CachedValue<T> onUpdate(ValueUpdateHandler<T> updateHandler) {
5284
dataManager.registerValueUpdateHandler(this.getKey(), update -> ThreadUtils.submit(() -> updateHandler.handle((ValueUpdate<T>) update)));
5385
return this;
5486
}
5587

88+
/**
89+
* Set the expiry time for this value.
90+
* After the expiry time has passed, the value will be deleted from Redis, and this {@link CachedValue} object will return the fallback value.
91+
*
92+
* @param seconds the number of seconds before the value expires, or -1 to disable expiry
93+
* @return this
94+
*/
5695
public CachedValue<T> withExpiry(int seconds) {
5796
this.expirySeconds = seconds;
5897
return this;
@@ -104,7 +143,11 @@ private T getFallbackValue() {
104143
return fallbackValue;
105144
}
106145

107-
146+
/**
147+
* Get the expiry time for this value.
148+
*
149+
* @return the expiry time in seconds, or -1 if expiry is disabled
150+
*/
108151
public int getExpirySeconds() {
109152
return expirySeconds;
110153
}
@@ -138,6 +181,12 @@ public void set(T value) {
138181
});
139182
}
140183

184+
/**
185+
* Set the value of this object.
186+
*
187+
* @param jedis the Jedis instance to use
188+
* @param value the value to set
189+
*/
141190
@Blocking
142191
public void set(Jedis jedis, T value) {
143192
CachedValueManager manager = dataManager.getCachedValueManager();
@@ -150,6 +199,12 @@ public void set(Jedis jedis, T value) {
150199
}
151200
}
152201

202+
/**
203+
* Get the identifying key for this value.
204+
* Note that this is only part of what is used to construct the Redis key, see {@link RedisKey#toString()}
205+
*
206+
* @return the identifying key
207+
*/
153208
public String getIdentifyingKey() {
154209
return identifyingKey;
155210
}

src/main/java/net/staticstudios/data/DataManager.java

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,12 @@
1010
import com.zaxxer.hikari.pool.HikariPool;
1111
import net.staticstudios.data.data.Data;
1212
import net.staticstudios.data.data.InitialValue;
13-
import net.staticstudios.data.data.Reference;
14-
import net.staticstudios.data.data.UniqueData;
1513
import net.staticstudios.data.data.collection.PersistentManyToManyCollection;
1614
import net.staticstudios.data.data.collection.PersistentUniqueDataCollection;
1715
import net.staticstudios.data.data.collection.SimplePersistentCollection;
16+
import net.staticstudios.data.data.value.InitialCachedValue;
17+
import net.staticstudios.data.data.value.InitialPersistentValue;
1818
import net.staticstudios.data.data.value.Value;
19-
import net.staticstudios.data.data.value.persistent.InitialPersistentValue;
20-
import net.staticstudios.data.data.value.persistent.PersistentValue;
21-
import net.staticstudios.data.data.value.redis.CachedValue;
22-
import net.staticstudios.data.data.value.redis.InitialCachedValue;
2319
import net.staticstudios.data.impl.CachedValueManager;
2420
import net.staticstudios.data.impl.PersistentCollectionManager;
2521
import net.staticstudios.data.impl.PersistentValueManager;
@@ -29,8 +25,7 @@
2925
import net.staticstudios.data.key.DataKey;
3026
import net.staticstudios.data.key.DatabaseKey;
3127
import net.staticstudios.data.primative.Primitives;
32-
import net.staticstudios.data.util.ReflectionUtils;
33-
import net.staticstudios.data.util.SQLLogger;
28+
import net.staticstudios.data.util.*;
3429
import net.staticstudios.utils.JedisProvider;
3530
import net.staticstudios.utils.ShutdownStage;
3631
import net.staticstudios.utils.ThreadUtils;
@@ -53,6 +48,9 @@
5348
import java.util.concurrent.CopyOnWriteArrayList;
5449
import java.util.stream.Collectors;
5550

51+
/**
52+
* Manages all data operations.
53+
*/
5654
public class DataManager extends SQLLogger {
5755
private static final Object NULL_MARKER = new Object();
5856
private final Logger logger = LoggerFactory.getLogger(DataManager.class);
@@ -75,6 +73,12 @@ public class DataManager extends SQLLogger {
7573
private final PersistentCollectionManager persistentCollectionManager;
7674
private final CachedValueManager cachedValueManager;
7775

76+
/**
77+
* Create a new data manager.
78+
*
79+
* @param poolConfig the HikariCP configuration to use for the internal connection pool
80+
* @param jedisProvider the Jedis provider for all Redis operations
81+
*/
7882
public DataManager(HikariConfig poolConfig, JedisProvider jedisProvider) {
7983
this.applicationName = "static_data_manager-" + UUID.randomUUID();
8084
this.cache = new ConcurrentHashMap<>();
@@ -182,6 +186,18 @@ public Collection<PersistentManyToManyCollection<?>> getAllDummyPersistentManyTo
182186
return new HashSet<>(dummyPersistentManyToManyCollectionMap.values());
183187
}
184188

189+
/**
190+
* Load all the data for a given class from the datasource(s) into the cache.
191+
* This method will recursively load all dependencies of the given class.
192+
* Note that calling this method registers a specific data type.
193+
* Without calling this method, the data manager will have no knowledge of the data type.
194+
* This should be called at the start of the application to ensure all data types are registered.
195+
* This method is inherently blocking.
196+
*
197+
* @param clazz The class to load data for
198+
* @param <T> The type of data to load
199+
* @return A list of all the loaded data
200+
*/
185201
@Blocking
186202
public <T extends UniqueData> List<T> loadAll(Class<T> clazz) {
187203
logger.debug("Registering: {}", clazz.getName());
@@ -311,6 +327,13 @@ public <T extends UniqueData> List<T> loadAll(Class<T> clazz) {
311327
return getAll(clazz);
312328
}
313329

330+
/**
331+
* Synchronously insert data into the datasource(s) and cache.
332+
*
333+
* @param holder The root holder of the data to insert
334+
* @param initialData The initial data to insert
335+
* @param <I> The type of initial data
336+
*/
314337
@Blocking
315338
@SafeVarargs
316339
public final <I extends InitialValue<?, ?>> void insert(UniqueData holder, I... initialData) {
@@ -328,6 +351,16 @@ public <T extends UniqueData> List<T> loadAll(Class<T> clazz) {
328351
}
329352
}
330353

354+
/**
355+
* Asynchronously insert data into the datasource(s) and cache.
356+
* The data will be instantly inserted into the cache, and then the datasource(s) will be updated asynchronously.
357+
* This method is non-blocking and will return immediately.
358+
* The cached data can be accessed immediately after this method is called.
359+
*
360+
* @param holder The root holder of the data to insert
361+
* @param initialData The initial data to insert
362+
* @param <I> The type of initial data
363+
*/
331364
@SafeVarargs
332365
public final <I extends InitialValue<?, ?>> void insertAsync(UniqueData holder, I... initialData) {
333366
InsertContext context = buildInsertContext(holder, initialData);
@@ -494,6 +527,14 @@ private void insertIntoDataSource(Connection connection, Jedis jedis, InsertCont
494527
cachedValueManager.setInRedis(jedis, new ArrayList<>(context.initialCachedValues().values()));
495528
}
496529

530+
/**
531+
* Delete data from the datasource(s) and cache.
532+
* This method will immediately delete the data from the cache, and then asynchronously delete the data from the datasource(s).
533+
* This method is non-blocking and will return immediately after deleting the data from the cache.
534+
* Data will be recursively deleted based off of the {@link DeletionStrategy} of each member of the data object.
535+
*
536+
* @param holder The root holder of the data to delete
537+
*/
497538
public void delete(UniqueData holder) {
498539
DeleteContext context = buildDeleteContext(holder);
499540
logger.trace("Deleting: {}", context);
@@ -512,6 +553,14 @@ public void delete(UniqueData holder) {
512553
});
513554
}
514555

556+
/**
557+
* Synchronously delete data from the datasource(s) and cache.
558+
* Data will be recursively deleted based off of the {@link DeletionStrategy} of each member of the data object.
559+
* This method is inherently blocking.
560+
*
561+
* @param holder The root holder of the data to delete
562+
*/
563+
@Blocking
515564
public void deleteSync(UniqueData holder) {
516565
DeleteContext context = buildDeleteContext(holder);
517566
logger.trace("Deleting: {}", context);
@@ -631,6 +680,13 @@ private void deleteFromDataSource(Connection connection, Jedis jedis, DeleteCont
631680
cachedValueManager.deleteFromRedis(jedis, context);
632681
}
633682

683+
/**
684+
* Get all data of a given type from the cache.
685+
*
686+
* @param clazz The class of data to get
687+
* @param <T> The type of data to get
688+
* @return A list of all the data of the given type in the cache
689+
*/
634690
public <T extends UniqueData> List<T> getAll(Class<T> clazz) {
635691
return uniqueDataIds.get(clazz).stream().map(id -> get(clazz, id)).toList();
636692
}
@@ -695,6 +751,9 @@ public synchronized void removeFromCacheIf(Predicate<DataKey> predicate) {
695751
keysToRemove.forEach(cache::remove);
696752
}
697753

754+
/**
755+
* Dump the internal cache to the log.
756+
*/
698757
public void dump() {
699758
logger.debug("Dumping cache:");
700759
for (Map.Entry<DataKey, CacheEntry> entry : cache.entrySet()) {
@@ -718,10 +777,26 @@ private void loadUniqueData(Connection connection, UniqueData dummyHolder) throw
718777
logger.info("Loaded {} instances of {}", uniqueDataIds.get(dummyHolder.getClass()).size(), dummyHolder.getClass().getName());
719778
}
720779

780+
/**
781+
* Get a data object from the cache.
782+
*
783+
* @param data The data object to get
784+
* @param <T> The value type stored in the data object
785+
* @return The data object from the cache
786+
* @throws DataDoesNotExistException If the data object does not exist in the cache
787+
*/
721788
public <T> T get(Data<T> data) throws DataDoesNotExistException {
722789
return get(data.getKey());
723790
}
724791

792+
/**
793+
* Get a data object from the cache.
794+
*
795+
* @param key The key of the data object to get
796+
* @param <T> The value type stored in the data object
797+
* @return The data object from the cache
798+
* @throws DataDoesNotExistException If the data object does not exist in the cache
799+
*/
725800
@SuppressWarnings("unchecked")
726801
public <T> T get(DataKey key) throws DataDoesNotExistException {
727802
CacheEntry cacheEntry = cache.get(key);
@@ -738,6 +813,14 @@ public <T> T get(DataKey key) throws DataDoesNotExistException {
738813
return (T) value;
739814
}
740815

816+
/**
817+
* Get a {@link UniqueData} object from the cache.
818+
*
819+
* @param clazz The class of the data object to get
820+
* @param id The id of the data object to get
821+
* @param <T> The type of data object to get
822+
* @return The data object from the cache, or null if it does not exist
823+
*/
741824
public <T extends UniqueData> T get(Class<T> clazz, UUID id) {
742825
if (id == null) {
743826
return null;
@@ -844,6 +927,16 @@ public void registerValueUpdateHandler(DataKey key, ValueUpdateHandler<?> handle
844927
valueUpdateHandlers.put(key, handler);
845928
}
846929

930+
/**
931+
* Get a connection from the connection pool.
932+
* This is an internal method and external callers should use it with caution.
933+
* Note that all connections in this pool have their application name set to a specific value.
934+
* Any updates made with a connection from this pool will not be received by this data manager instance.
935+
* Most callers should use their own connection pool.
936+
*
937+
* @return A connection from the connection pool
938+
* @throws SQLException If a connection cannot be obtained
939+
*/
847940
public Connection getConnection() throws SQLException {
848941
return connectionPool.getConnection();
849942
}

src/main/java/net/staticstudios/data/Deletable.java

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/main/java/net/staticstudios/data/InsertContext.java

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)