Skip to content
Open
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
65 changes: 65 additions & 0 deletions src/main/java/com/programmerdan/minecraft/wordbank/NameRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.programmerdan.minecraft.wordbank;

import com.programmerdan.minecraft.wordbank.data.WordBankData;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Objects;
import java.util.logging.Level;

/**
*
* @author caucow
*/
public class NameRecord {
public final String key;
public final String value;
private boolean marked;

public NameRecord(String key, String value, boolean marked) {
this.key = Objects.requireNonNull(key);
this.value = Objects.requireNonNull(value);
this.marked = marked;
}

/**
* Marks the wordbank key/value pair as used in the database, along with
* player UUID and the item type it was applied to.
* @param wbplugin WordBank plugin (for database access)
* @param playerId player UUID
* @param itemType item type name was applied to
* @param force force a database update with the current pID and itemType
* regardless of whether this name is already marked
*/
public void mark(WordBank wbplugin, String playerId, String itemType, boolean force) {
if (marked && !force) {
return;
}
marked = true;
if (wbplugin.config().hasDB()) {
try {
if (wbplugin.config().isDebug()) wbplugin.logger().info(" - Inserting item record");
long startTime = 0, endTime = 0;
startTime = System.nanoTime();
try (
Connection connection = wbplugin.data().getConnection();
PreparedStatement insert = connection.prepareStatement(WordBankData.insert)) {
insert.setString(1, key);
insert.setString(2, playerId);
insert.setString(3, itemType);
insert.setString(4, value);
insert.executeUpdate();
insert.close();
endTime = System.nanoTime();
if (wbplugin.config().isDebug()) wbplugin.logger().log(Level.INFO, "Wrote key/value {0}={1} to database in {2}ms", new Object[] { key, value, (endTime - startTime) / 1_000_000.0F });
}
} catch (SQLException se) {
wbplugin.logger().log(Level.WARNING, "Failed to insert key utilization", se);
}
}
}

public boolean isMarked() {
return marked;
}
}
62 changes: 62 additions & 0 deletions src/main/java/com/programmerdan/minecraft/wordbank/WordBank.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.programmerdan.minecraft.wordbank;

import com.google.common.cache.LoadingCache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -12,6 +15,12 @@
import com.programmerdan.minecraft.wordbank.actions.ActionListener;
import com.programmerdan.minecraft.wordbank.actions.CommandListener;
import com.programmerdan.minecraft.wordbank.data.WordBankData;
import com.programmerdan.minecraft.wordbank.util.NameConstructor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.concurrent.TimeUnit;
import org.bukkit.ChatColor;

/**
* See README.md for details. Simple Bukkit plugin using some Cool Stuff under the hood.
Expand All @@ -25,6 +34,7 @@ public class WordBank extends JavaPlugin {
private static WordBank plugin;
private WordBankConfig config;
private WordBankData data;
private LoadingCache<String, NameRecord> nameCache; // laggy database hits? that's not very cache money tbh

public void onEnable() {
WordBank.plugin = this;
Expand All @@ -40,6 +50,54 @@ public void onEnable() {

// Do DB provision
data = new WordBankData();
nameCache = CacheBuilder.newBuilder()
.expireAfterAccess(config.getNamecacheInvalidateMinutes(), TimeUnit.MINUTES)
.expireAfterWrite(config.getNamecacheInvalidateMinutes(), TimeUnit.MINUTES)
.maximumSize(config.getNamecacheMaxSize())
.build(new CacheLoader<String, NameRecord>() {
@Override
public NameRecord load(String key) throws Exception {
String value = null;
long startTime = 0, endTime = 0;
if (config().hasDB()) {
try {
startTime = System.nanoTime();
try (Connection connection = data().getConnection();
PreparedStatement statement = connection.prepareStatement(WordBankData.getvalue)) {
statement.setString(1, key);
try (ResultSet rs = statement.executeQuery()) {
if (rs.next()) {
value = rs.getString("val");
}
}
statement.close();
}
endTime = System.nanoTime();
} catch (SQLException se) {
logger().log(Level.WARNING, "Failed to retrieve key/value data!", se);
if (config().isFailRenameOnDbError()) {
throw se;
}
}
if (value != null) {
// value exists in database, return record with marked=TRUE
NameRecord record = new NameRecord(key, value, true);
if (config().isDebug()) logger().log(Level.INFO, "Retrieved value {0}={1} from database in {2}ms", new Object[] { record.key, record.value, (endTime - startTime) / 1_000_000.0F });
return record;
} else {
// value did not exist in database. debug time and carry on
if (config().isDebug()) logger().log(Level.INFO, "Database entry not found for {0} in {1}ms", new Object[] { key, (endTime - startTime) / 1_000_000.0F });
}
}
// no value in database, return record with marked=FALSE
startTime = System.nanoTime();
NameRecord record = NameConstructor.buildName(key);
endTime = System.nanoTime();
if (config().isDebug()) logger().log(Level.INFO, "Generated name for value {0}={1} in {2}ms", new Object[] { record.key, record.value, (endTime - startTime) / 1_000_000.0F });
return record;
}
}
);
Bukkit.getPluginManager().registerEvents(new ActionListener(), this);
plugin.getCommand("wordbank").setExecutor(new CommandListener());
}
Expand Down Expand Up @@ -70,4 +128,8 @@ public WordBankConfig config() {
public WordBankData data() {
return data;
}

public LoadingCache<String, NameRecord> nameCache() {
return nameCache;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class WordBankConfig {
private boolean debug;
private WordBank plugin;
private long confirm_delay;
private boolean fail_rename_on_db_error;
private int namecache_invalidate_minutes;
private int namecache_max_size;
private boolean dblog_all_item_marks;
private boolean prevent_dblookup_spam;

public WordBankConfig(ConfigurationSection config) throws InvalidPluginException {
this(config, null);
Expand Down Expand Up @@ -68,6 +73,23 @@ public WordBankConfig(ConfigurationSection config, WordBank plugin) throws Inval

this.confirm_delay = config.getLong("confirm_delay", 10000l);

// true if, should the database be enabled AND throw an exception when
// getting a value for a key name, wordbank should skip trying to generate
// a new value for that key (prevents possible ambiguity in names if
// the configs change and the che cache can't access the database)
this.fail_rename_on_db_error = config.getBoolean("fail_rename_on_db_error", true);
this.namecache_invalidate_minutes = config.getInt("namecache_invalidate_minutes", 5);
this.namecache_max_size = config.getInt("namecache_max_size", 500);
// Before the change to use async load/generate, every time a player
// used wordbank to generate a name for an item, it added a new entry to
// the database regardless of whether an entry already existed with that
// wbkey. Setting this to true will keep that old behavior (for...
// counting number of times a name is used or something? idk)
this.dblog_all_item_marks = config.getBoolean("dblog_all_item_marks", false);
// Set to true if players are spamming wordbank too fast and slowing the
// database.
this.prevent_dblookup_spam = config.getBoolean("prevent_dblookup_spam", true);

// dbconfig
this.db_config = null;
ConfigurationSection db = config.getConfigurationSection("db");
Expand Down Expand Up @@ -150,4 +172,24 @@ public boolean hasDB() {
public HikariConfig database() {
return this.db_config;
}

public boolean isFailRenameOnDbError() {
return fail_rename_on_db_error;
}

public int getNamecacheInvalidateMinutes() {
return namecache_invalidate_minutes;
}

public int getNamecacheMaxSize() {
return namecache_max_size;
}

public boolean isDBLogAllItemMarks() {
return dblog_all_item_marks;
}

public boolean isPreventDBLookupSpam() {
return prevent_dblookup_spam;
}
}
Loading