Very minimal testing has been done, but Citadel is now no longer a
steaming heap of bricks.  Aside from fixing bugs, I've changed tabs to 4
spaces in both Citadel.java and my Dao extension.
This commit is contained in:
Charles Smith
2012-09-29 13:21:11 -07:00
parent d0bdc8e3ca
commit 77fe240f3b
2 changed files with 237 additions and 228 deletions

View File

@@ -71,95 +71,95 @@ public class Citadel extends JavaPlugin {
private static Citadel plugin;
public boolean onCommand(CommandSender sender, Command command, String label, String[] args){
return commandHandler.dispatch(sender, label, args);
return commandHandler.dispatch(sender, label, args);
}
public void onEnable() {
plugin = this;
configManager.load();
dao = new CitadelCachingDao(this);
dao.updateDatabase();
setUpStorage();
registerCommands();
registerEvents();
configManager.load();
for(Player player : getServer().getOnlinePlayers()){
memberManager.addOnlinePlayer(player);
memberManager.addOnlinePlayer(player);
}
try {
Metrics metrics = new Metrics(this);
metrics.start();
} catch (IOException e) {
// Failed to submit the stats :-(
System.out.println("failed");
System.out.println("failed");
}
log.info("[Citadel] Citadel is now enabled.");
}
public void onDisable() {
//There should be some interface that CitadelCachingDao can implement that does this automatically on disable:
//There should be some interface that CitadelCachingDao can implement that does this automatically on disable:
//I don't want to do this as close() or finalize() because I want to make sure the database connection is still alive.
if( dao instanceof CitadelCachingDao ){
if( dao instanceof CitadelCachingDao ){
((CitadelCachingDao)dao).shutDown();
}
log.info("[Citadel] Citadel is now disabled.");
}
public void setUpStorage(){
GroupStorage groupStorage = new GroupStorage(dao);
groupManager.setStorage(groupStorage);
PersonalGroupStorage personalGroupStorage = new PersonalGroupStorage(dao);
personalGroupManager.setStorage(personalGroupStorage);
MemberStorage memberStorage = new MemberStorage(dao);
memberManager.setStorage(memberStorage);
ReinforcementStorage reinforcementStorage = new ReinforcementStorage(dao);
reinforcementManager.setStorage(reinforcementStorage);
GroupStorage groupStorage = new GroupStorage(dao);
groupManager.setStorage(groupStorage);
PersonalGroupStorage personalGroupStorage = new PersonalGroupStorage(dao);
personalGroupManager.setStorage(personalGroupStorage);
MemberStorage memberStorage = new MemberStorage(dao);
memberManager.setStorage(memberStorage);
ReinforcementStorage reinforcementStorage = new ReinforcementStorage(dao);
reinforcementManager.setStorage(reinforcementStorage);
}
public void registerCommands(){
commandHandler.addCommand(new AddModCommand());
commandHandler.addCommand(new AllowCommand());
commandHandler.addCommand(new BypassCommand());
commandHandler.addCommand(new CreateCommand());
commandHandler.addCommand(new DeleteCommand());
commandHandler.addCommand(new DisallowCommand());
commandHandler.addCommand(new FortifyCommand());
commandHandler.addCommand(new GroupCommand());
commandHandler.addCommand(new GroupInfoCommand());
commandHandler.addCommand(new GroupsCommand());
//commandHandler.addCommand(new Help())
commandHandler.addCommand(new InfoCommand());
commandHandler.addCommand(new JoinCommand());
commandHandler.addCommand(new LeaveCommand());
commandHandler.addCommand(new MaterialsCommand());
commandHandler.addCommand(new MembersCommand());
commandHandler.addCommand(new ModeratorsCommand());
commandHandler.addCommand(new NonReinforceableCommand());
commandHandler.addCommand(new OffCommand());
commandHandler.addCommand(new PasswordCommand());
commandHandler.addCommand(new PrivateCommand());
commandHandler.addCommand(new PublicCommand());
commandHandler.addCommand(new ReinforceCommand());
commandHandler.addCommand(new RemoveModCommand());
commandHandler.addCommand(new SecurableCommand());
commandHandler.addCommand(new StatsCommand());
commandHandler.addCommand(new TransferCommand());
commandHandler.addCommand(new VersionCommand());
commandHandler.addCommand(new AddModCommand());
commandHandler.addCommand(new AllowCommand());
commandHandler.addCommand(new BypassCommand());
commandHandler.addCommand(new CreateCommand());
commandHandler.addCommand(new DeleteCommand());
commandHandler.addCommand(new DisallowCommand());
commandHandler.addCommand(new FortifyCommand());
commandHandler.addCommand(new GroupCommand());
commandHandler.addCommand(new GroupInfoCommand());
commandHandler.addCommand(new GroupsCommand());
//commandHandler.addCommand(new Help())
commandHandler.addCommand(new InfoCommand());
commandHandler.addCommand(new JoinCommand());
commandHandler.addCommand(new LeaveCommand());
commandHandler.addCommand(new MaterialsCommand());
commandHandler.addCommand(new MembersCommand());
commandHandler.addCommand(new ModeratorsCommand());
commandHandler.addCommand(new NonReinforceableCommand());
commandHandler.addCommand(new OffCommand());
commandHandler.addCommand(new PasswordCommand());
commandHandler.addCommand(new PrivateCommand());
commandHandler.addCommand(new PublicCommand());
commandHandler.addCommand(new ReinforceCommand());
commandHandler.addCommand(new RemoveModCommand());
commandHandler.addCommand(new SecurableCommand());
commandHandler.addCommand(new StatsCommand());
commandHandler.addCommand(new TransferCommand());
commandHandler.addCommand(new VersionCommand());
}
public void registerEvents(){
try {
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BlockListener(), this);
pm.registerEvents(new PlayerListener(), this);
pm.registerEvents(new EntityListener(), this);
}
catch(Exception e)
{
printStackTrace(e);
}
try {
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BlockListener(), this);
pm.registerEvents(new PlayerListener(), this);
pm.registerEvents(new EntityListener(), this);
}
catch(Exception e)
{
printStackTrace(e);
}
}
@Override
@@ -176,41 +176,41 @@ public class Citadel extends JavaPlugin {
}
public static void info(String message){
if(configManager.getVerboseLogging()){
log.info("[Citadel] " + message);
}
if(configManager.getVerboseLogging()){
log.info("[Citadel] " + message);
}
}
public static void severe(String message){
log.severe("[Citadel] " + message);
log.severe("[Citadel] " + message);
}
public static void warning(String message){
log.warning("[Citadel] " + message);
log.warning("[Citadel] " + message);
}
public static GroupManager getGroupManager(){
return groupManager;
return groupManager;
}
public static PersonalGroupManager getPersonalGroupManager(){
return personalGroupManager;
return personalGroupManager;
}
public static MemberManager getMemberManager(){
return memberManager;
return memberManager;
}
public static ReinforcementManager getReinforcementManager(){
return reinforcementManager;
return reinforcementManager;
}
public static ConfigManager getConfigManager(){
return configManager;
return configManager;
}
public static Citadel getPlugin(){
return plugin;
return plugin;
}
public static void printStackTrace(Throwable t)
@@ -237,4 +237,4 @@ public class Citadel extends JavaPlugin {
severe(" ======= SNIP HERE =======");
severe("");
}
}
}

View File

@@ -5,6 +5,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;
import org.bukkit.Chunk;
import org.bukkit.Location;
@@ -16,166 +17,174 @@ import com.untamedears.citadel.entity.Reinforcement;
import com.untamedears.citadel.entity.ReinforcementKey;
public class CitadelCachingDao extends CitadelDao{
HashMap<Chunk, ChunkCache> cachesByChunk;
LinkedList<ChunkCache> cachesByTime;
HashMap<Chunk, ChunkCache> cachesByChunk;
LinkedList<ChunkCache> cachesByTime;
long maxAge;
int maxChunks;
public CitadelCachingDao(JavaPlugin plugin){
super(plugin);
maxAge = Citadel.getConfigManager().getCacheMaxAge();
maxChunks = Citadel.getConfigManager().getCacheMaxChunks();
}
public ChunkCache getCacheOfBlock( Block block ) throws RefuseToPreventThrashingException {
ChunkCache cache = cachesByChunk.get( block.getChunk() );
if( cache != null ){
cachesByTime.remove(cache);
cachesByTime.add(cache);
}else{
if( cachesByTime.size() > maxChunks ){
throw new RefuseToPreventThrashingException();
}
cache = new ChunkCache( block.getChunk() );
cachesByChunk.put( block.getChunk() , cache );
cachesByTime.add( cache );
ChunkCache last = cachesByTime.getLast();
while( last.getLastPlooked() + maxAge < System.currentTimeMillis() ||
cachesByTime.size() > maxChunks ){
last.flush();
cachesByTime.remove(last);
cachesByChunk.remove(last.getChunk());
}
}
return cache;
}
@Override
public Reinforcement findReinforcement( Location location ){
return findReinforcement(location.getBlock());
}
@Override
public Reinforcement findReinforcement( Block block ){
try{
ChunkCache cache = getCacheOfBlock( block );
return cache.findReinforcement(block);
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
return super.findReinforcement( block );
}
}
@Override
public void save(Object o){
if( o instanceof Reinforcement ){
Reinforcement r = (Reinforcement)o;
try{
getCacheOfBlock( r.getBlock() ).save( r );
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
super.save( r );
}
}else{
super.save( o );
}
}
@Override
public void delete(Object o){
if( o instanceof Reinforcement ){
Reinforcement r = (Reinforcement)o;
try{
getCacheOfBlock( r.getBlock() ).save( r );
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
super.delete( r );
}
}else{
super.delete( o );
}
}
//There should be some interface to implement that calls this automatically.
public void shutDown(){
while( !cachesByTime.isEmpty() ){
cachesByTime.pop().flush();
}
}
private class ChunkCache {
TreeSet<Reinforcement> toSave;//if RAM isn't a problem replace this with a HashSet.
TreeSet<Reinforcement> toDelete;//if RAM isn't a problem replace this with a HashSet.
TreeSet<Reinforcement> cache;//if RAM isn't a problem replace this with a HashSet.
Chunk chunk;
long lastPlooked;
public ChunkCache( Chunk chunk ){
this.chunk = chunk;
cache = new TreeSet<Reinforcement>( findReinforcementsInChunk( chunk ));
}
public Reinforcement findReinforcement( Location l ){
return findReinforcement(l.getBlock());
}
public Reinforcement findReinforcement( Block block ){
lastPlooked = System.currentTimeMillis();
Reinforcement key = new Reinforcement();
key.setId(new ReinforcementKey(block));
Reinforcement r = cache.floor( key );
if( r.equals(key) ){
toSave.add(r);
return r;
}else{
return null;
}
}
public void save( Reinforcement r ){
lastPlooked = System.currentTimeMillis();
if( !cache.add( r )){
//Yes, this makes sense.
//If we're editing the cache, then our new "r" will equal the old "r"
//because reinforements are compared by their ReinforcementKeys, and the
//new and old Reinforcements have the same key. So we're removing the reinforcement
//from the set that matches the new "r" (which the old "r" does) and then adding
//the new "r".
cache.remove( r );
cache.add( r );
}
toDelete.remove( r );
toSave.add( r );
}
public void delete( Reinforcement r ){
lastPlooked = System.currentTimeMillis();
cache.remove( r );
toSave.remove( r );
toDelete.add( r );
}
public void flush(){
getDatabase().save(toSave);
getDatabase().delete(toDelete);
}
public long getLastPlooked(){
return lastPlooked;
}
public Chunk getChunk(){
return chunk;
}
}
private class RefuseToPreventThrashingException extends Exception{
}
long maxAge;
int maxChunks;
public CitadelCachingDao(JavaPlugin plugin){
super(plugin);
cachesByTime = new LinkedList<ChunkCache>();
cachesByChunk = new HashMap<Chunk, ChunkCache>();
maxAge = Citadel.getConfigManager().getCacheMaxAge();
maxChunks = Citadel.getConfigManager().getCacheMaxChunks();
}
public ChunkCache getCacheOfBlock( Block block ) throws RefuseToPreventThrashingException {
ChunkCache cache = cachesByChunk.get( block.getChunk() );
if( cache != null ){
cachesByTime.remove(cache);
cachesByTime.add(cache);
}else{
if( cachesByTime.size() > maxChunks ){
throw new RefuseToPreventThrashingException();
}
cache = new ChunkCache( block.getChunk() );
cachesByChunk.put( block.getChunk() , cache );
cachesByTime.add( cache );
ChunkCache last = cachesByTime.getLast();
while( (last.getLastPlooked() + maxAge < System.currentTimeMillis() ||
cachesByTime.size() > maxChunks) &&
!cachesByTime.isEmpty() ){
last.flush();
cachesByTime.remove(last);
cachesByChunk.remove(last.getChunk());
}
}
return cache;
}
@Override
public Reinforcement findReinforcement( Location location ){
return findReinforcement(location.getBlock());
}
@Override
public Reinforcement findReinforcement( Block block ){
try{
ChunkCache cache = getCacheOfBlock( block );
return cache.findReinforcement(block);
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
return super.findReinforcement( block );
}
}
@Override
public void save(Object o){
if( o instanceof Reinforcement ){
Reinforcement r = (Reinforcement)o;
try{
getCacheOfBlock( r.getBlock() ).save( r );
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
super.save( r );
}
}else{
super.save( o );
}
}
@Override
public void delete(Object o){
if( o instanceof Reinforcement ){
Reinforcement r = (Reinforcement)o;
try{
getCacheOfBlock( r.getBlock() ).save( r );
}catch( RefuseToPreventThrashingException e ){
Citadel.warning( "Bypassing RAM cache to prevent database thrashing. Consider raising caching.max_chunks");
super.delete( r );
}
}else{
super.delete( o );
}
}
//There should be some interface to implement that calls this automatically.
public void shutDown(){
while( !cachesByTime.isEmpty() ){
cachesByTime.pop().flush();
}
}
private class ChunkCache {
TreeSet<Reinforcement> toSave;//if RAM isn't a problem replace this with a HashSet.
TreeSet<Reinforcement> toDelete;//if RAM isn't a problem replace this with a HashSet.
TreeSet<Reinforcement> cache;//if RAM isn't a problem replace this with a HashSet.
Chunk chunk;
long lastPlooked;
public ChunkCache( Chunk chunk ){
this.chunk = chunk;
cache = new TreeSet<Reinforcement>( findReinforcementsInChunk( chunk ));
toSave = new TreeSet<Reinforcement>();
toDelete = new TreeSet<Reinforcement>();
lastPlooked = System.currentTimeMillis();
}
public Reinforcement findReinforcement( Location l ){
return findReinforcement(l.getBlock());
}
public Reinforcement findReinforcement( Block block ){
lastPlooked = System.currentTimeMillis();
Reinforcement key = new Reinforcement();
key.setId(new ReinforcementKey(block));
Reinforcement r = cache.floor( key );
if( r != null && r.equals(key) ){
toSave.add(r);
return r;
}else{
return null;
}
}
public void save( Reinforcement r ){
lastPlooked = System.currentTimeMillis();
if( !cache.add( r )){
//Yes, this makes sense.
//If we're editing the cache, then our new "r" will equal the old "r"
//because reinforements are compared by their ReinforcementKeys, and the
//new and old Reinforcements have the same key. So we're removing the reinforcement
//from the set that matches the new "r" (which the old "r" does) and then adding
//the new "r".
cache.remove( r );
cache.add( r );
}
toDelete.remove( r );
toSave.add( r );
}
public void delete( Reinforcement r ){
lastPlooked = System.currentTimeMillis();
cache.remove( r );
toSave.remove( r );
toDelete.add( r );
}
public void flush(){
getDatabase().save(toSave);
getDatabase().delete(toDelete);
}
public long getLastPlooked(){
return lastPlooked;
}
public Chunk getChunk(){
return chunk;
}
}
private class RefuseToPreventThrashingException extends Exception{
}
}