Better entity change logging

This commit is contained in:
BuildTools 2015-11-27 16:13:48 +01:00 committed by Olof Larsson
parent 0e8b43f8ea
commit 603db8079b
7 changed files with 95 additions and 86 deletions

View File

@ -102,4 +102,6 @@ public class MassiveCoreMConf extends Entity<MassiveCoreMConf>
public volatile long millisBetweenLocalPoll = 5_000; public volatile long millisBetweenLocalPoll = 5_000;
public volatile long millisBetweenRemotePollWithoutPusher = 5_000; public volatile long millisBetweenRemotePollWithoutPusher = 5_000;
public volatile long millisBetweenRemotePollWithPusher = 30_000; public volatile long millisBetweenRemotePollWithPusher = 30_000;
public boolean warnOnLocalAlter = false;
} }

View File

@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentSkipListMap;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.massivecraft.massivecore.MassiveCore; import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.MassiveCoreMConf;
import com.massivecraft.massivecore.MassivePlugin; import com.massivecraft.massivecore.MassivePlugin;
import com.massivecraft.massivecore.NaturalOrderComparator; import com.massivecraft.massivecore.NaturalOrderComparator;
import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.collections.MassiveList;
@ -195,14 +196,6 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
@Override public int getLocalPollInfrequency() { return this.localPollInfrequency; } @Override public int getLocalPollInfrequency() { return this.localPollInfrequency; }
@Override public void setLocalPollInfrequency(int infrequence) { this.localPollInfrequency = infrequence; } @Override public void setLocalPollInfrequency(int infrequence) { this.localPollInfrequency = infrequence; }
// We often try to call Entity#changed to inform that an entity has been changed locally.
// And on some Colls we expect it to always be done.
// However we cannot be sure, but if we expect to always do it
// then we tell the collection to notify us if we failed to call Entity#changed.
protected boolean warnOnLocalAlter = true;
@Override public boolean isWarningOnLocalAlter() { return this.warnOnLocalAlter; }
@Override public void setWarnOnLocalAlter(boolean warnOnLocalAlter) { this.warnOnLocalAlter = warnOnLocalAlter; }
// Should that instance be saved or not? // Should that instance be saved or not?
// If it is default it should not be saved. // If it is default it should not be saved.
@Override @Override
@ -734,12 +727,21 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
public Modification syncIdFixed(String id, Modification modification, Entry<JsonObject, Long> remoteEntry) public Modification syncIdFixed(String id, Modification modification, Entry<JsonObject, Long> remoteEntry)
{ {
if (id == null) throw new NullPointerException("id"); if (id == null) throw new NullPointerException("id");
if (modification == null || modification == Modification.UNKNOWN) if (modification == null || modification.isUnknown())
{ {
Long remoteMtime = null; Long remoteMtime = null;
if (remoteEntry != null) remoteMtime = remoteEntry.getValue(); if (remoteEntry != null) remoteMtime = remoteEntry.getValue();
modification = this.examineIdFixed(id, remoteMtime); Modification actualModification = this.examineIdFixed(id, remoteMtime);
if (MassiveCoreMConf.get().warnOnLocalAlter && modification == Modification.UNKNOWN_LOG && actualModification.isModified())
{
E entity = this.id2entity.get(id);
if (entity != null)
{
this.logModification(entity);
}
}
modification = actualModification;
} }
if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " syncronising " + modification + " on " + id); if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " syncronising " + modification + " on " + id);
@ -791,8 +793,48 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
return modification; return modification;
} }
protected void logModification(E entity)
{
JsonObject lastRaw = entity.getLastRaw();
JsonObject currentRaw = this.getGson().toJsonTree(entity).getAsJsonObject();
List<String> changes = new MassiveList<>();
// Check removal and modification.
for (Entry<String, JsonElement> entry : lastRaw.entrySet())
{
String name = entry.getKey();
JsonElement currentValue = currentRaw.get(name);
if (currentValue == null)
{
changes.add(Txt.parse("<b>%s", name));
continue;
}
JsonElement lastValue = entry.getValue();
if (MStore.equal(currentValue, lastValue)) continue;
changes.add(Txt.parse("<i>%s", name));
}
// Check for addition
for (Entry<String, JsonElement> entry : currentRaw.entrySet())
{
String name = entry.getKey();
if (lastRaw.has(name)) continue;
changes.add(Txt.parse("<g>%s", name));
}
// Log
if (changes.isEmpty()) return;
changes.add(0, Txt.parse("<pink>%s", this.getDebugName()));
changes.add(1, Txt.parse("<aqua>%s", entity.getId()));
String change = Txt.implode(changes, Txt.parse("<silver> | "));
String message = Txt.parse("<b>[Unreported Modification] %s", change);
MassiveCore.get().log(message);
}
@Override @Override
public void identifyModifications(boolean sure) public void identifyModifications(Modification veto)
{ {
if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for all changes"); if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for all changes");
@ -812,40 +854,40 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
// Check for modifications // Check for modifications
for (Entry<String, Long> entry : id2RemoteMtime.entrySet()) for (Entry<String, Long> entry : id2RemoteMtime.entrySet())
{ {
this.identifyModificationFixed(entry.getKey(), entry.getValue(), sure); this.identifyModificationFixed(entry.getKey(), entry.getValue(), veto);
} }
} }
@Override @Override
public void identifyModificationFixed(String id, Long remoteMtime, boolean sure) public void identifyModificationFixed(String id, Long remoteMtime, Modification veto)
{ {
if (id == null) throw new NullPointerException("id"); if (id == null) throw new NullPointerException("id");
Modification modification = this.examineIdFixed(id, remoteMtime); Modification modification = this.examineIdFixed(id, remoteMtime);
this.storeModificationIdentification(id, modification, sure); this.storeModificationIdentification(id, modification, veto);
} }
@Override @Override
public void identifyLocalModifications(boolean sure) public void identifyLocalModifications(Modification veto)
{ {
if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for local changes"); if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for local changes");
for (String id : id2entity.keySet()) for (String id : id2entity.keySet())
{ {
this.identifyLocalModificationFixed(id, sure); this.identifyLocalModificationFixed(id, veto);
} }
} }
@Override @Override
public void identifyLocalModificationFixed(String id, boolean sure) public void identifyLocalModificationFixed(String id, Modification veto)
{ {
if (id == null) throw new NullPointerException("id"); if (id == null) throw new NullPointerException("id");
Modification modification = this.examineIdLocalFixed(id); Modification modification = this.examineIdLocalFixed(id);
this.storeModificationIdentification(id, modification, sure); this.storeModificationIdentification(id, modification, veto);
} }
@Override @Override
public void identifyRemoteModifications(boolean sure) public void identifyRemoteModifications(Modification veto)
{ {
if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for remote changes"); if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " polling for remote changes");
// Get remote id2mtime snapshot // Get remote id2mtime snapshot
@ -866,72 +908,29 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
// Check for modifications // Check for modifications
for (Entry<String, Long> entry : id2RemoteMtime.entrySet()) for (Entry<String, Long> entry : id2RemoteMtime.entrySet())
{ {
this.identifyRemoteModificationFixed(entry.getKey(), entry.getValue(), sure); this.identifyRemoteModificationFixed(entry.getKey(), entry.getValue(), veto);
} }
} }
@Override @Override
public void identifyRemoteModificationFixed(String id, Long remoteMtime, boolean sure) public void identifyRemoteModificationFixed(String id, Long remoteMtime, Modification veto)
{ {
if (id == null) throw new NullPointerException("id"); if (id == null) throw new NullPointerException("id");
Modification modification = this.examineIdRemoteFixed(id, remoteMtime); Modification modification = this.examineIdRemoteFixed(id, remoteMtime);
this.storeModificationIdentification(id, modification, sure); this.storeModificationIdentification(id, modification, veto);
} }
protected void storeModificationIdentification(String id, Modification modification, boolean sure) protected void storeModificationIdentification(String id, Modification modification, Modification veto)
{ {
if (this.isWarningOnLocalAlter() && modification == Modification.LOCAL_ALTER)
{
MassiveCore.get().log("A local alter was spotted in " + this.getDebugName() + " on " + id);
E entity = this.get(id);
JsonObject lastRaw = entity.getLastRaw();
JsonObject currentRaw = this.getGson().toJsonTree(entity, this.getEntityClass()).getAsJsonObject();
this.logModification(lastRaw, currentRaw);
}
if (modification.isModified()) if (modification.isModified())
{ {
if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " identified " + modification + " on " + id); if (MStore.DEBUG_ENABLED) System.out.println(this.getDebugName() + " identified " + modification + " on " + id);
if (!sure && ! modification.isSafe()) modification = Modification.UNKNOWN; if (veto != null && ! modification.isSafe()) modification = veto;
this.putIdentifiedModificationFixed(id, modification); this.putIdentifiedModificationFixed(id, modification);
} }
} }
protected void logModification(JsonObject lastRaw, JsonObject currentRaw)
{
List<String> changes = new MassiveList<>();
// Check removal and modification.
for (Entry<String, JsonElement> entry : lastRaw.entrySet())
{
String name = entry.getKey();
JsonElement currentValue = currentRaw.get(name);
if (currentValue == null)
{
changes.add(String.format("Removed %s", name));
continue;
}
JsonElement lastValue = entry.getValue();
if (MStore.equal(currentValue, lastValue)) continue;
changes.add(String.format("Changed %s: %s -> %s", name, lastValue, currentValue));
}
// Check for addition
for (Entry<String, JsonElement> entry : currentRaw.entrySet())
{
String name = entry.getKey();
if (lastRaw.has(name)) continue;
changes.add(String.format("Added %s: %s", name, entry.getValue()));
}
// Log
for (String change : changes)
{
MassiveCore.get().log(change);
}
}
@Override @Override
public void syncIdentified() public void syncIdentified()
{ {
@ -946,7 +945,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
@Override @Override
public void syncAll() public void syncAll()
{ {
this.identifyModifications(true); this.identifyModifications(null);
this.syncIdentified(); this.syncIdentified();
} }

View File

@ -96,9 +96,6 @@ public interface CollInterface<E extends Entity<E>> extends Named
public int getLocalPollInfrequency(); public int getLocalPollInfrequency();
public void setLocalPollInfrequency(int frequency); public void setLocalPollInfrequency(int frequency);
public boolean isWarningOnLocalAlter();
public void setWarnOnLocalAlter(boolean warnOnLocalAlter);
// A default entity will not be saved. // A default entity will not be saved.
// This is often used together with creative collections to save disc space. // This is often used together with creative collections to save disc space.
public boolean isDefault(E entity); public boolean isDefault(E entity);
@ -208,14 +205,14 @@ public interface CollInterface<E extends Entity<E>> extends Named
public void syncAll(); public void syncAll();
// Identity // Identity
public void identifyModifications(boolean sure); public void identifyModifications(Modification veto);
public void identifyModificationFixed(String id, Long remoteMtime, boolean sure); public void identifyModificationFixed(String id, Long remoteMtime, Modification veto);
public void identifyLocalModifications(boolean sure); public void identifyLocalModifications(Modification veto);
public void identifyLocalModificationFixed(String id, boolean sure); public void identifyLocalModificationFixed(String id, Modification veto);
public void identifyRemoteModifications(boolean sure); public void identifyRemoteModifications(Modification veto);
public void identifyRemoteModificationFixed(String id, Long remoteMtime, boolean sure); public void identifyRemoteModificationFixed(String id, Long remoteMtime, Modification veto);
// Init // Init
public void initLoadAllFromRemote(); public void initLoadAllFromRemote();

View File

@ -7,14 +7,15 @@ public enum Modification
// ENUM // ENUM
// -------------------------------------------- // // -------------------------------------------- //
LOCAL_ALTER (true, 3), LOCAL_ALTER (true, 4),
LOCAL_ATTACH (true, 7), LOCAL_ATTACH (true, 8),
LOCAL_DETACH (true, 8), LOCAL_DETACH (true, 9),
REMOTE_ALTER (true, 4), REMOTE_ALTER (true, 5),
REMOTE_ATTACH (true, 5), REMOTE_ATTACH (true, 6),
REMOTE_DETACH (true, 6), REMOTE_DETACH (true, 7),
NONE (false, 1), NONE (false, 1),
UNKNOWN (false, 2), UNKNOWN (false, 3),
UNKNOWN_LOG(false, 2),
; ;
// -------------------------------------------- // // -------------------------------------------- //
@ -75,4 +76,13 @@ public enum Modification
{ {
return this.getPriority() >= TOP_PRIORITY; return this.getPriority() >= TOP_PRIORITY;
} }
// -------------------------------------------- //
// UNKNOWN
// -------------------------------------------- //
public boolean isUnknown()
{
return this == Modification.UNKNOWN || this == Modification.UNKNOWN_LOG;
}
} }

View File

@ -35,7 +35,7 @@ public class ModificationPollerLocal extends ModificationPollerAbstract
{ {
if (iterationCount % coll.getLocalPollInfrequency() == 0) if (iterationCount % coll.getLocalPollInfrequency() == 0)
{ {
coll.identifyLocalModifications(false); coll.identifyLocalModifications(Modification.UNKNOWN_LOG);
return true; return true;
} }
return false; return false;

View File

@ -42,7 +42,7 @@ public class ModificationPollerRemote extends ModificationPollerAbstract
public boolean poll(Coll<?> coll, long iterationCount) public boolean poll(Coll<?> coll, long iterationCount)
{ {
//TODO: This could probably be true. //TODO: This could probably be true.
coll.identifyRemoteModifications(false); coll.identifyRemoteModifications(Modification.UNKNOWN);
return true; return true;
} }

View File

@ -125,6 +125,7 @@ public class PusherCollFlatfile extends Thread implements PusherColl
// It was modified locally. // It was modified locally.
case NONE: case NONE:
case UNKNOWN: case UNKNOWN:
case UNKNOWN_LOG:
return; return;
// It was modified remotely. // It was modified remotely.