Skip to content

Commit

Permalink
5.1.3: New Value system for data to fix bugs
Browse files Browse the repository at this point in the history
There was a bug with the cache where it couldn't detect when a value was being set to null (as it was being removed from the cache).
This fixes that and potentially other bugs that were occurring due to similar reasons.
  • Loading branch information
srnyx committed Nov 6, 2024
1 parent f719e31 commit 6679650
Show file tree
Hide file tree
Showing 18 changed files with 396 additions and 215 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins {
}

// Don't forget to change AnnoyingPlugin#ANNOYING_API_VERSION when updating
setupMC("xyz.srnyx", "5.1.2", "General purpose API with tons of features", replacementFiles = setOf("plugin.yml", "AnnoyingStats.class"))
setupMC("xyz.srnyx", "5.1.3", "General purpose API with tons of features")
spigotAPI("1.8.8")

// Dependencies
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ public void log(@NotNull LogRecord logRecord) {
}
};
/**
* The version of the Annoying API the plugin is using
* The version of Annoying API the plugin is using
*/
@NotNull public static final SemanticVersion ANNOYING_API_VERSION = new SemanticVersion(5, 1, 2);
@NotNull public static final SemanticVersion ANNOYING_API_VERSION = new SemanticVersion(5, 1, 3);
/**
* The Minecraft version the server is running
*/
Expand Down Expand Up @@ -178,7 +178,7 @@ public final void onDisable() {
if (dataManager.dialect instanceof SQLDialect) try {
((SQLDialect) dataManager.dialect).connection.close();
} catch (final SQLException e) {
log(Level.SEVERE, "Failed to close the database connection", e);
log(Level.SEVERE, "&cFailed to close the database connection", e);
}
}

Expand Down Expand Up @@ -299,8 +299,8 @@ private void enablePlugin() {
});
}

// Start cache saving on interval if enabled
if (dataManager != null && dataManager.storageConfig.cache.saveOn.contains(StorageConfig.SaveOn.INTERVAL)) dataManager.startCacheSavingOnInterval();
// Enable/disable interval cache saving (depending on config)
if (dataManager != null) dataManager.toggleIntervalCacheSaving();

// Custom onEnable
enable();
Expand All @@ -326,6 +326,7 @@ public void disablePlugin() {
public void reloadPlugin() {
loadMessages();
loadDataManger(dataManager != null && dataManager.storageConfig.cache.saveOn.contains(StorageConfig.SaveOn.RELOAD));
if (dataManager != null) dataManager.toggleIntervalCacheSaving();
reload();
}

Expand Down Expand Up @@ -419,7 +420,6 @@ public void loadDataManger(boolean saveCache) {

// Attempt database migration
dataManager = dataManager.attemptDatabaseMigration();

// Create tables/columns
if (dataManager.dialect instanceof SQLDialect) ((SQLDialect) dataManager.dialect).createTablesKeys(options.dataOptions.tables);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/xyz/srnyx/annoyingapi/AnnoyingUpdate.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class AnnoyingUpdate extends Stringable implements Annoyable {
*/
@NotNull private final String userAgent;
/**
* The platforms the plugin is available on. Currently only {@link PluginPlatform.Platform#MODRINTH} and {@link PluginPlatform.Platform#SPIGOT} are supported
* The platforms the plugin is available on. Currently only {@link PluginPlatform.Platform#MODRINTH Modrinth}, {@link PluginPlatform.Platform#HANGAR Hangar}, and {@link PluginPlatform.Platform#SPIGOT Spigot} are supported
*/
@NotNull private final PluginPlatform.Multi platforms;
/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/xyz/srnyx/annoyingapi/PluginPlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public enum Platform {
/**
* <a href="https://hangar.papermc.io/">{@code https://hangar.papermc.io/}</a>
* <p>Slug
* <p><b>Example:</b> {@code AnnoyingAPI}
* <p><b>Example:</b> {@code srnyx/AnnoyingAPI}
*/
HANGAR(true),
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ public class CooldownManager extends Stringable {
*/
@NotNull public final Set<AnnoyingCooldown> cooldowns = new HashSet<>();

/**
* Constructs a new cooldown manager
*/
public CooldownManager() {
// Only exists to give the constructor a Javadoc
}

/**
* Get all cooldowns with the given type
*
Expand Down
20 changes: 11 additions & 9 deletions src/main/java/xyz/srnyx/annoyingapi/data/StringData.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.AnnoyingPlugin;
import xyz.srnyx.annoyingapi.storage.FailedSet;
import xyz.srnyx.annoyingapi.storage.Value;
import xyz.srnyx.annoyingapi.storage.dialects.Dialect;
import xyz.srnyx.annoyingapi.options.DataOptions;

import java.util.Optional;
import java.util.logging.Level;


Expand Down Expand Up @@ -89,27 +90,28 @@ public StringData(@NotNull AnnoyingPlugin plugin, @NotNull OfflinePlayer player)
public String get(@NotNull String key) {
// Get the data from the cache
if (useCache) {
final Optional<String> cached = dialect.getFromCache(table, target, key);
if (cached.isPresent()) return cached.get();
final Value cached = dialect.getFromCache(table, target, key);
if (cached != null) return cached.value;
}

// Get the data from the database
final String data = dialect.getFromDatabase(table, target, key).orElse(null);
if (useCache) dialect.setToCache(table, target, key, data);
if (useCache) dialect.setToCache(table, target, key, new Value(data));
return data;
}

@Override
protected boolean set(@NotNull String key, @NotNull String value) {
// Set the data in the cache
if (useCache) {
dialect.setToCache(table, target, key, value);
dialect.setToCache(table, target, key, new Value(value));
return true;
}

// Set the data in the database
if (!dialect.setToDatabase(table, target, key, value)) {
AnnoyingPlugin.log(Level.SEVERE, "Failed to set " + key + " for " + target + " in " + table + ". Make sure you added the table/column to DataOptions!");
final FailedSet failed = dialect.setToDatabase(table, target, key, value);
if (failed != null) {
AnnoyingPlugin.log(Level.SEVERE, "&cFailed to set &4" + key + "&c for &4" + target + "&c in &4" + table + "&c. DEVELOPERS: Make sure you added the table/column to DataOptions!", failed.exception);
return false;
}
return true;
Expand All @@ -119,13 +121,13 @@ protected boolean set(@NotNull String key, @NotNull String value) {
public boolean remove(@NotNull String key) {
// Remove the data from the cache
if (useCache) {
dialect.removeFromCache(table, target, key);
dialect.markRemovedInCache(table, target, key);
return true;
}

// Remove the data from the database
if (!dialect.removeValueFromDatabase(table, target, key)) {
AnnoyingPlugin.log(Level.SEVERE, "Failed to remove " + key + " for " + target + " in " + table + ". Make sure you added the table/column to DataOptions!");
AnnoyingPlugin.log(Level.SEVERE, "&cFailed to remove &4" + key + "&c for &4" + target + "&c in &4" + table + "&c. DEVELOPERS: Make sure you added the table/column to DataOptions!");
return false;
}
return true;
Expand Down
30 changes: 21 additions & 9 deletions src/main/java/xyz/srnyx/annoyingapi/storage/DataManager.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package xyz.srnyx.annoyingapi.storage;

import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.AnnoyingPlugin;
import xyz.srnyx.annoyingapi.storage.dialects.Dialect;
Expand All @@ -13,7 +15,6 @@
import java.io.IOException;
import java.nio.file.Files;
import java.sql.SQLException;
import java.util.Map;
import java.util.logging.Level;


Expand All @@ -37,6 +38,12 @@ public class DataManager {
* The table prefix for the database (only for remote connections)
*/
@NotNull public final String tablePrefix;
/**
* The task that saves the cache on an interval
*
* @see DataManager#toggleIntervalCacheSaving()
*/
@Nullable public BukkitTask cacheSavingTask;

/**
* Connect to the configured database and create the pre-defined tables/columns
Expand Down Expand Up @@ -66,11 +73,19 @@ public String getTableName(@NotNull String tableName) {
}

/**
* Starts the asynchronous task to save the cache on an interval
* If saving the cache on an interval is enabled, this will start the asynchronous task to do that
* <br>If the feature is disabled, this will cancel the task if it exists
*/
public void startCacheSavingOnInterval() {
final long interval = storageConfig.cache.interval;
Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, dialect::saveCache, interval, interval);
public void toggleIntervalCacheSaving() {
// Cancel ongoing task if one exists
if (cacheSavingTask != null) cacheSavingTask.cancel();
// Disable
if (!storageConfig.cache.saveOn.contains(StorageConfig.SaveOn.INTERVAL)) {
cacheSavingTask = null;
return;
}
// Enable
cacheSavingTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, dialect::saveCache, storageConfig.cache.interval, storageConfig.cache.interval);
}

/**
Expand Down Expand Up @@ -108,10 +123,7 @@ public DataManager attemptDatabaseMigration() {
// NEW: Create missing tables/columns
if (newManager.dialect instanceof SQLDialect) ((SQLDialect) newManager.dialect).createTablesKeys(migrationData.tablesKeys);
// NEW: Save values to new database (log failures)
for (final Map.Entry<String, Map<String, Map<String, String>>> entry : newManager.dialect.setToDatabase(migrationData.data).entrySet()) {
final String table = entry.getKey();
for (final Map.Entry<String, Map<String, String>> entry1 : entry.getValue().entrySet()) AnnoyingPlugin.log(Level.SEVERE, storageConfig.migrationLogPrefix + "Failed to set values for &4" + entry1.getKey() + "&c in table &4" + table + "&c: &4" + entry1.getValue());
}
for (final FailedSet failure : newManager.dialect.setToDatabase(migrationData.data)) AnnoyingPlugin.log(Level.SEVERE, storageConfig.migrationLogPrefix + "Failed to set &4" + failure.column + "&c for &4" + failure.target + "&c in table &4" + failure.table + "&c to &4" + failure.value, failure.exception);
} else {
AnnoyingPlugin.log(Level.SEVERE, storageConfig.migrationLogPrefix + "Found no data to migrate! This may or may not be an error...");
}
Expand Down
64 changes: 64 additions & 0 deletions src/main/java/xyz/srnyx/annoyingapi/storage/FailedSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package xyz.srnyx.annoyingapi.storage;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


/**
* Represents a failed set operation
*/
public class FailedSet {
/**
* The table that the set operation failed on
*/
@NotNull public final String table;
/**
* The target that the set operation failed for
*/
@NotNull public final String target;
/**
* The column that the set operation failed on
*/
@NotNull public final String column;
/**
* The value that the set operation failed with
*/
@Nullable public final String value;
/**
* The exception that occurred while attempting to set the value
*/
@Nullable public final Throwable exception;

/**
* Constructs a new failed set with the given table, target, column, and value
*
* @param table {@link #table}
* @param target {@link #target}
* @param column {@link #column}
* @param value {@link #value}
*/
public FailedSet(@NotNull String table, @NotNull String target, @NotNull String column, @Nullable String value) {
this.table = table;
this.target = target;
this.column = column;
this.value = value;
this.exception = null;
}

/**
* Constructs a new failed set with the given table, target, column, value, and exception
*
* @param table {@link #table}
* @param target {@link #target}
* @param column {@link #column}
* @param value {@link #value}
* @param exception {@link #exception}
*/
public FailedSet(@NotNull String table, @NotNull String target, @NotNull String column, @Nullable String value, @NotNull Throwable exception) {
this.table = table;
this.target = target;
this.column = column;
this.value = value;
this.exception = exception;
}
}
37 changes: 37 additions & 0 deletions src/main/java/xyz/srnyx/annoyingapi/storage/Value.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package xyz.srnyx.annoyingapi.storage;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


/**
* Represents a value that may be null
* <br>This is needed so that the plugin can know whether a value was cached or not for data (because null could be a valid value)
*/
public class Value {
/**
* The value
*/
@Nullable public final String value;

/**
* Constructs a new value with the given value
*
* @param value the value
*/
public Value(@Nullable String value) {
this.value = value;
}

/**
* Constructs a new value with a null value
*/
public Value() {
this.value = null;
}

@Override @NotNull
public String toString() {
return value == null ? "null" : value;
}
}
Loading

0 comments on commit 6679650

Please sign in to comment.