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
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@
@Target(ElementType.FIELD)
public @interface Identifier {
String value();

boolean index() default false;
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {

allprojects {
group = 'net.staticstudios'
version = '3.1.6-SNAPSHOT'
version = '3.2.0-SNAPSHOT'

repositories {
mavenCentral()
Expand Down
2 changes: 2 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ dependencies {
implementation 'com.h2database:h2:2.3.232'
implementation 'org.jetbrains:annotations:24.0.1'

implementation("com.github.ben-manes.caffeine:caffeine:3.2.3")

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
Expand Down
20 changes: 18 additions & 2 deletions core/src/main/java/net/staticstudios/data/CachedValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ public ProxyCachedValue(UniqueData holder, Class<T> dataType) {
public void setDelegate(CachedValueMetadata metadata, AbstractCachedValue<T> delegate) {
Preconditions.checkNotNull(delegate, "Delegate cannot be null");
Preconditions.checkState(this.delegate == null, "Delegate is already set");

if (fallback != null && !metadata.hasValidatedFallbackSupplier()) {
LambdaUtils.assertLambdaDoesntCapture(fallback, List.of(UniqueData.class), null);
metadata.setValidatedFallbackSupplier(true);
}

if (refresher != null && !metadata.hasValidatedRefresher()) {
LambdaUtils.assertLambdaDoesntCapture(refresher, List.of(UniqueData.class), null);
metadata.setValidatedRefresher(true);
}

if (!metadata.hasValidatedUpdateHandlers()) {
for (ValueUpdateHandlerWrapper<?, T> handler : updateHandlers) {
LambdaUtils.assertLambdaDoesntCapture(handler.getHandler(), List.of(UniqueData.class), null);
}
metadata.setValidatedUpdateHandlers(true);
}

delegate.setFallback(this.fallback);
delegate.setRefresher(refresher);
this.delegate = delegate;
Expand Down Expand Up @@ -89,7 +107,6 @@ public CachedValue<T> supplyFallback(Supplier<T> fallback) {
throw new UnsupportedOperationException("Cannot set fallback after initialization");
}
Preconditions.checkNotNull(fallback, "Fallback supplier cannot be null");
LambdaUtils.assertLambdaDoesntCapture(fallback, List.of(UniqueData.class), null);
this.fallback = fallback;
return this;
}
Expand All @@ -98,7 +115,6 @@ public CachedValue<T> supplyFallback(Supplier<T> fallback) {
@Override
public <U extends UniqueData> CachedValue<T> refresher(Class<U> clazz, CachedValueRefresher<U, T> refresher) {
Preconditions.checkArgument(delegate == null, "Cannot dynamically add a refresher after the holder has been initialized!");
LambdaUtils.assertLambdaDoesntCapture(refresher, List.of(UniqueData.class), null);
this.refresher = (CachedValueRefresher<UniqueData, T>) refresher;
return this;
}
Expand Down
240 changes: 225 additions & 15 deletions core/src/main/java/net/staticstudios/data/DataManager.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package net.staticstudios.data;

import com.google.common.base.Preconditions;
import net.staticstudios.data.util.CollectionChangeHandler;
import net.staticstudios.data.util.CollectionChangeHandlerWrapper;
import net.staticstudios.data.util.PersistentCollectionMetadata;
import net.staticstudios.data.util.Relation;
import net.staticstudios.data.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -65,6 +62,14 @@ public Class<T> getDataType() {

public void setDelegate(PersistentCollectionMetadata metadata, PersistentCollection<T> delegate) {
Preconditions.checkState(this.delegate == null, "Delegate has already been set");

if (!metadata.hasValidatedChangeHandlers()) {
for (CollectionChangeHandlerWrapper<?, ?> wrapper : changeHandlers) {
LambdaUtils.assertLambdaDoesntCapture(wrapper.getHandler(), List.of(UniqueData.class), null);
}
metadata.setValidatedChangeHandlers(true);
}

this.delegate = delegate;
holder.getDataManager().registerCollectionChangeHandlers(metadata, changeHandlers);
}
Expand Down
14 changes: 9 additions & 5 deletions core/src/main/java/net/staticstudios/data/PersistentValue.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package net.staticstudios.data;

import com.google.common.base.Preconditions;
import net.staticstudios.data.util.PersistentValueMetadata;
import net.staticstudios.data.util.Value;
import net.staticstudios.data.util.ValueUpdateHandler;
import net.staticstudios.data.util.ValueUpdateHandlerWrapper;
import net.staticstudios.data.util.*;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
Expand All @@ -16,7 +13,6 @@
* @param <T>
*/
public interface PersistentValue<T> extends Value<T> {
//todo: use caffeine to further cache pvs, provided we are using the H2 data accessor. allow us to toggle this on and off when setting up the data manager

static <T> PersistentValue<T> of(UniqueData holder, Class<T> dataType) {
return new ProxyPersistentValue<>(holder, dataType);
Expand All @@ -42,6 +38,14 @@ public ProxyPersistentValue(UniqueData holder, Class<T> dataType) {
public void setDelegate(PersistentValueMetadata metadata, PersistentValue<T> delegate) {
Preconditions.checkNotNull(delegate, "Delegate cannot be null");
Preconditions.checkState(this.delegate == null, "Delegate is already set");

if (!metadata.hasValidatedUpdateHandlers()) {
for (ValueUpdateHandlerWrapper<?, ?> wrapper : updateHandlers) {
LambdaUtils.assertLambdaDoesntCapture(wrapper.getHandler(), List.of(UniqueData.class), null);
}
metadata.setValidatedUpdateHandlers(true);
}

this.delegate = delegate;
holder.getDataManager().registerPersistentValueUpdateHandlers(metadata, updateHandlers);
}
Expand Down
13 changes: 9 additions & 4 deletions core/src/main/java/net/staticstudios/data/Reference.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package net.staticstudios.data;

import com.google.common.base.Preconditions;
import net.staticstudios.data.util.ReferenceMetadata;
import net.staticstudios.data.util.ReferenceUpdateHandler;
import net.staticstudios.data.util.ReferenceUpdateHandlerWrapper;
import net.staticstudios.data.util.Relation;
import net.staticstudios.data.util.*;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.AccessFlag;
Expand Down Expand Up @@ -71,6 +68,14 @@ public void set(T value) {

public void setDelegate(ReferenceMetadata metadata, Reference<T> delegate) {
Preconditions.checkState(this.delegate == null, "Delegate has already been set");

if (!metadata.hasValidatedUpdateHandlers()) {
for (ReferenceUpdateHandlerWrapper<?, ?> wrapper : updateHandlers) {
LambdaUtils.assertLambdaDoesntCapture(wrapper.getHandler(), List.of(UniqueData.class), null);
}
metadata.setValidatedUpdateHandlers(true);
}

this.delegate = delegate;
holder.getDataManager().registerReferenceUpdateHandlers(metadata, updateHandlers);
}
Expand Down
11 changes: 11 additions & 0 deletions core/src/main/java/net/staticstudios/data/StaticData.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,15 @@ public static void flushTaskQueue() {
assertInit();
DataManager.getInstance().flushTaskQueue();
}


/**
* Retrieves the current performance statistics of the StaticData system, including metrics such as queries per second and updates per second.
*
* @return a StaticDataStatistics object containing the current performance metrics of the StaticData system
*/
public static StaticDataStatistics getStatistics() {
assertInit();
return DataManager.getInstance().getStatistics();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package net.staticstudios.data;

public class StaticDataStatistics {
private long queriesPerSecond = -1;
private long updatesPerSecond = -1;
private int relationCacheSize = -1;
private int dependenciesToRelationsCacheMappingSize = -1;
private int cellCacheSize = -1;
private int dependenciesToCellCacheMappingSize = -1;

public void setQueriesPerSecond(long queriesPerSecond) {
this.queriesPerSecond = queriesPerSecond;
}

public void setUpdatesPerSecond(long updatesPerSecond) {
this.updatesPerSecond = updatesPerSecond;
}

public void setRelationCacheSize(int relationCacheSideSize) {
this.relationCacheSize = relationCacheSideSize;
}

public void setDependenciesToRelationsCacheMappingSize(int dependenciesToRelationsCacheMappingSize) {
this.dependenciesToRelationsCacheMappingSize = dependenciesToRelationsCacheMappingSize;
}

public void setCellCacheSize(int cellCacheSize) {
this.cellCacheSize = cellCacheSize;
}

public void setDependenciesToCellCacheMappingSize(int dependenciesToCellCacheMappingSize) {
this.dependenciesToCellCacheMappingSize = dependenciesToCellCacheMappingSize;
}

public long getQueriesPerSecond() {
return queriesPerSecond;
}

public long getUpdatesPerSecond() {
return updatesPerSecond;
}

public long getOperationsPerSecond() {
return queriesPerSecond + updatesPerSecond;
}

public int getRelationCacheSize() {
return relationCacheSize;
}

public int getDependenciesToRelationsCacheMappingSize() {
return dependenciesToRelationsCacheMappingSize;
}

public int getCellCacheSize() {
return cellCacheSize;
}

public int getDependenciesToCellCacheMappingSize() {
return dependenciesToCellCacheMappingSize;
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package net.staticstudios.data.impl;

import net.staticstudios.data.InsertMode;
import net.staticstudios.data.StaticDataStatistics;
import net.staticstudios.data.parse.DDLStatement;
import net.staticstudios.data.util.ColumnValuePairs;
import net.staticstudios.data.util.SQLTransaction;
import net.staticstudios.data.util.SQlStatement;
import org.intellij.lang.annotations.Language;
Expand All @@ -27,11 +29,13 @@ default void executeUpdate(SQLTransaction.Statement statement, List<Object> valu

void postDDL() throws SQLException;

@Nullable String getRedisValue(String key);
@Nullable String getRedisValue(String holderSchema, String holderTable, String identifier, ColumnValuePairs idColumns);

void setRedisValue(String key, String value, int expirationSeconds);
void setRedisValue(String holderSchema, String holderTable, String identifier, ColumnValuePairs idColumns, String value, int expirationSeconds);

void discoverRedisKeys(List<String> partialRedisKeys);

void resync();

void populateStatistics(StaticDataStatistics stats);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,27 @@ public static <T> CachedValueImpl<T> create(UniqueData holder, Class<T> dataType

public static <T extends UniqueData> void delegate(T instance) {
UniqueDataMetadata metadata = instance.getDataManager().getMetadata(instance.getClass());
for (FieldInstancePair<@Nullable CachedValue> pair : ReflectionUtils.getFieldInstancePairs(instance, CachedValue.class)) {
CachedValueMetadata pvMetadata = metadata.cachedValueMetadata().get(pair.field());
if (pair.instance() instanceof CachedValue.ProxyCachedValue<?> proxyCv) {
CachedValueImpl.createAndDelegate(proxyCv, pvMetadata);
} else {
pair.field().setAccessible(true);
try {
pair.field().set(instance, CachedValueImpl.create(instance, ReflectionUtils.getGenericType(pair.field()), pvMetadata));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
try {
for (var entry : metadata.cachedValueMetadata().entrySet()) {
Field field = entry.getKey();
CachedValueMetadata cvMetadata = entry.getValue();

Object value = field.get(instance);
if (value instanceof CachedValue.ProxyCachedValue<?> proxyCv) {
CachedValueImpl.createAndDelegate(proxyCv, cvMetadata);
} else {
field.set(instance, CachedValueImpl.create(instance, cvMetadata.type(), cvMetadata));
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}

public static <T extends UniqueData> Map<Field, CachedValueMetadata> extractMetadata(String holderSchema, String holderTable, Class<T> clazz) {
Map<Field, CachedValueMetadata> metadataMap = new HashMap<>();
for (Field field : ReflectionUtils.getFields(clazz, CachedValue.class)) {
field.setAccessible(true);
metadataMap.put(field, extractMetadata(holderSchema, holderTable, clazz, field));
}
return metadataMap;
Expand All @@ -76,7 +79,8 @@ public static <T extends UniqueData> CachedValueMetadata extractMetadata(String
expireAfterSeconds = expireAfterAnnotation.value();
}

return new CachedValueMetadata(clazz, holderSchema, holderTable, ValueUtils.parseValue(identifierAnnotation.value()), expireAfterSeconds);

return new CachedValueMetadata(clazz, holderSchema, holderTable, ValueUtils.parseValue(identifierAnnotation.value()), ReflectionUtils.getGenericType(field), expireAfterSeconds);
}


Expand Down
Loading