MassiveStore improvements
This commit is contained in:
parent
525d904f8f
commit
e16333b822
@ -3,8 +3,10 @@ package com.massivecraft.massivecore;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -14,6 +16,8 @@ import org.bukkit.event.EventPriority;
|
|||||||
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
||||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result;
|
||||||
import org.bukkit.event.player.PlayerKickEvent;
|
import org.bukkit.event.player.PlayerKickEvent;
|
||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
import org.bukkit.event.player.PlayerChatTabCompleteEvent;
|
import org.bukkit.event.player.PlayerChatTabCompleteEvent;
|
||||||
@ -34,6 +38,7 @@ import com.massivecraft.massivecore.store.Coll;
|
|||||||
import com.massivecraft.massivecore.store.SenderColl;
|
import com.massivecraft.massivecore.store.SenderColl;
|
||||||
import com.massivecraft.massivecore.util.IdUtil;
|
import com.massivecraft.massivecore.util.IdUtil;
|
||||||
import com.massivecraft.massivecore.util.SmokeUtil;
|
import com.massivecraft.massivecore.util.SmokeUtil;
|
||||||
|
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||||
|
|
||||||
public class MassiveCoreEngineMain extends EngineAbstract
|
public class MassiveCoreEngineMain extends EngineAbstract
|
||||||
{
|
{
|
||||||
@ -320,35 +325,114 @@ public class MassiveCoreEngineMain extends EngineAbstract
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// MASSIVE STORE: LOGIN SYNC
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// This section handles the automatic sync of a players corresponding massive store entries on login.
|
||||||
|
// If possible the database IO is made during the AsyncPlayerPreLoginEvent to offloat the main server thread.
|
||||||
|
|
||||||
|
protected Map<String, Map<SenderColl<?>, Entry<JsonElement, Long>>> idToRemoteEntries = new ConcurrentHashMap<String, Map<SenderColl<?>, Entry<JsonElement, Long>>>();
|
||||||
|
|
||||||
|
// Intended to be ran asynchronously.
|
||||||
|
public void storeRemoteEntries(String playerId)
|
||||||
|
{
|
||||||
|
// Create remote entries ...
|
||||||
|
Map<SenderColl<?>, Entry<JsonElement, Long>> remoteEntries = createRemoteEntries(playerId);
|
||||||
|
|
||||||
|
// ... and store them.
|
||||||
|
this.idToRemoteEntries.put(playerId, remoteEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intended to be ran synchronously.
|
||||||
|
// It will use remoteEntries from AsyncPlayerPreLoginEvent if possible.
|
||||||
|
// If no such remoteEntries are available it will create them and thus lock the main server thread a bit.
|
||||||
|
public Map<SenderColl<?>, Entry<JsonElement, Long>> getRemoteEntries(String playerId)
|
||||||
|
{
|
||||||
|
// If there are stored remote entries we used those ...
|
||||||
|
Map<SenderColl<?>, Entry<JsonElement, Long>> ret = idToRemoteEntries.remove(playerId);
|
||||||
|
if (ret != null) return ret;
|
||||||
|
|
||||||
|
// ... otherwise we create brand new ones.
|
||||||
|
return createRemoteEntries(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the two methods above.
|
||||||
|
public Map<SenderColl<?>, Entry<JsonElement, Long>> createRemoteEntries(String playerId)
|
||||||
|
{
|
||||||
|
// Create Ret
|
||||||
|
Map<SenderColl<?>, Entry<JsonElement, Long>> ret = new HashMap<SenderColl<?>, Entry<JsonElement, Long>>();
|
||||||
|
|
||||||
|
// Fill Ret
|
||||||
|
for (final SenderColl<?> coll : Coll.getSenderInstances())
|
||||||
|
{
|
||||||
|
Entry<JsonElement, Long> remoteEntry = coll.getDb().load(coll, playerId);
|
||||||
|
ret.put(coll, remoteEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return Ret
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void massiveStoreLoginSync(AsyncPlayerPreLoginEvent event)
|
||||||
|
{
|
||||||
|
// DEBUG
|
||||||
|
// long before = System.nanoTime();
|
||||||
|
|
||||||
|
// If the login was allowed ...
|
||||||
|
if (event.getLoginResult() != Result.ALLOWED) return;
|
||||||
|
|
||||||
|
// ... get player id ...
|
||||||
|
final String playerId = event.getUniqueId().toString();
|
||||||
|
|
||||||
|
// ... and store the remote entries.
|
||||||
|
this.storeRemoteEntries(playerId);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
// long after = System.nanoTime();
|
||||||
|
// long duration = after - before;
|
||||||
|
// double ms = (double)duration / 1000000D;
|
||||||
|
// String message = Txt.parse("<i>AsyncPlayerPreLoginEvent for %s <i>took <h>%.2f <i>ms.", event.getName(), ms);
|
||||||
|
// MassiveCore.get().log(message);
|
||||||
|
// NOTE: I get values between 5 and 20 ms.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can not be cancelled.
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void massiveStoreLoginSync(PlayerLoginEvent event)
|
||||||
|
{
|
||||||
|
// Get player id ...
|
||||||
|
final String playerId = event.getPlayer().getUniqueId().toString();
|
||||||
|
|
||||||
|
// ... get remote entries ...
|
||||||
|
Map<SenderColl<?>, Entry<JsonElement, Long>> remoteEntries = getRemoteEntries(playerId);
|
||||||
|
|
||||||
|
// ... and sync each of them.
|
||||||
|
for (Entry<SenderColl<?>, Entry<JsonElement, Long>> entry : remoteEntries.entrySet())
|
||||||
|
{
|
||||||
|
SenderColl<?> coll = entry.getKey();
|
||||||
|
Entry<JsonElement, Long> remoteEntry = entry.getValue();
|
||||||
|
coll.syncId(playerId, null, remoteEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// SYNC PLAYER ON LOGON AND LEAVE
|
// SYNC PLAYER ON LOGON AND LEAVE
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
|
||||||
public void syncOnPlayerLogin(PlayerLoginEvent event)
|
|
||||||
{
|
|
||||||
//MassiveCore.get().log("LOWEST syncOnPlayerLogin", event.getPlayer().getName());
|
|
||||||
this.syncAllForPlayer(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void syncOnPlayerLeave(EventMassiveCorePlayerLeave event)
|
public void syncOnPlayerLeave(EventMassiveCorePlayerLeave event)
|
||||||
{
|
{
|
||||||
//MassiveCore.get().log("MONITOR syncOnPlayerLeave", event.getPlayer().getName());
|
// TODO: This is going to take quite a bit of power :(
|
||||||
this.syncAllForPlayer(event.getPlayer());
|
this.syncAllForPlayer(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncAllForPlayer(Player player)
|
public void syncAllForPlayer(Player player)
|
||||||
{
|
{
|
||||||
// TODO: For now we sync them both!
|
|
||||||
String playerName = player.getName();
|
|
||||||
String playerId = player.getUniqueId().toString();
|
String playerId = player.getUniqueId().toString();
|
||||||
for (Coll<?> coll : Coll.getInstances())
|
for (SenderColl<?> coll : Coll.getSenderInstances())
|
||||||
{
|
{
|
||||||
if (!(coll instanceof SenderColl)) continue;
|
coll.syncId(playerId);
|
||||||
SenderColl<?> pcoll = (SenderColl<?>)coll;
|
|
||||||
pcoll.syncId(playerName);
|
|
||||||
pcoll.syncId(playerId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import com.massivecraft.massivecore.cmd.MassiveCommand;
|
|||||||
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
|
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
|
||||||
import com.massivecraft.massivecore.store.Coll;
|
import com.massivecraft.massivecore.store.Coll;
|
||||||
import com.massivecraft.massivecore.store.Db;
|
import com.massivecraft.massivecore.store.Db;
|
||||||
import com.massivecraft.massivecore.store.Driver;
|
|
||||||
import com.massivecraft.massivecore.store.MStore;
|
import com.massivecraft.massivecore.store.MStore;
|
||||||
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||||
|
|
||||||
@ -58,9 +57,6 @@ public class CmdMassiveCoreStoreCopydb extends MassiveCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare
|
// Prepare
|
||||||
final Driver fromDriver = fromDb.getDriver();
|
|
||||||
final Driver toDriver = toDb.getDriver();
|
|
||||||
|
|
||||||
Set<String> collnames = fromDb.getCollnames();
|
Set<String> collnames = fromDb.getCollnames();
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
@ -76,11 +72,11 @@ public class CmdMassiveCoreStoreCopydb extends MassiveCommand
|
|||||||
final Coll<?> fromColl = new Coll<Object>(collname, Object.class, fromDb, MassiveCore.get());
|
final Coll<?> fromColl = new Coll<Object>(collname, Object.class, fromDb, MassiveCore.get());
|
||||||
final Coll<?> toColl = new Coll<Object>(collname, Object.class, toDb, MassiveCore.get());
|
final Coll<?> toColl = new Coll<Object>(collname, Object.class, toDb, MassiveCore.get());
|
||||||
|
|
||||||
Collection<String> ids = fromDriver.getIds(fromColl);
|
Collection<String> ids = fromDb.getIds(fromColl);
|
||||||
msg("<i>Now copying collection <h>%d/%d %s <i>with <h>%d <i>documents.", countCollCurrent, countCollTotal, collname, ids.size());
|
msg("<i>Now copying collection <h>%d/%d %s <i>with <h>%d <i>documents.", countCollCurrent, countCollTotal, collname, ids.size());
|
||||||
|
|
||||||
// Do a load check to verify we have access to this folder.
|
// Do a load check to verify we have access to this folder.
|
||||||
if (ids.size() > 0 && fromDriver.load(fromColl, ids.iterator().next()) == null)
|
if (ids.size() > 0 && fromDb.load(fromColl, ids.iterator().next()) == null)
|
||||||
{
|
{
|
||||||
msg("<b>Skipping <h>%s <b>since could not load data.", collname);
|
msg("<b>Skipping <h>%s <b>since could not load data.", collname);
|
||||||
continue;
|
continue;
|
||||||
@ -88,8 +84,8 @@ public class CmdMassiveCoreStoreCopydb extends MassiveCommand
|
|||||||
|
|
||||||
for (String id : ids)
|
for (String id : ids)
|
||||||
{
|
{
|
||||||
Entry<JsonElement, Long> data = fromDriver.load(fromColl, id);
|
Entry<JsonElement, Long> data = fromDb.load(fromColl, id);
|
||||||
toDriver.save(toColl, id, data.getKey());
|
toDb.save(toColl, id, data.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long after = System.currentTimeMillis();
|
long after = System.currentTimeMillis();
|
||||||
|
@ -54,7 +54,7 @@ public class CmdMassiveCoreStoreListcolls extends MassiveCommand
|
|||||||
collnames.addAll(db.getCollnames());
|
collnames.addAll(db.getCollnames());
|
||||||
|
|
||||||
// Do it!
|
// Do it!
|
||||||
msg(Txt.titleize("Collections in "+db.getName()));
|
msg(Txt.titleize("Collections in "+db.getDbName()));
|
||||||
for (String collname : collnames)
|
for (String collname : collnames)
|
||||||
{
|
{
|
||||||
String message = Txt.parse("<h>") + collname;
|
String message = Txt.parse("<h>") + collname;
|
||||||
@ -63,7 +63,7 @@ public class CmdMassiveCoreStoreListcolls extends MassiveCommand
|
|||||||
|
|
||||||
for (Coll<?> collCandidate : Coll.getInstances())
|
for (Coll<?> collCandidate : Coll.getInstances())
|
||||||
{
|
{
|
||||||
if (!collCandidate.getName().equals(collname)) continue;
|
if ( ! collCandidate.getName().equals(collname)) continue;
|
||||||
if (collCandidate.getDb() != db) continue;
|
if (collCandidate.getDb() != db) continue;
|
||||||
coll = collCandidate;
|
coll = collCandidate;
|
||||||
break;
|
break;
|
||||||
|
@ -72,8 +72,8 @@ public class CmdMassiveCoreStoreStats extends MassiveCommand
|
|||||||
msg("<k>Entity Count: <v>%d", coll.getIds().size());
|
msg("<k>Entity Count: <v>%d", coll.getIds().size());
|
||||||
msg("<k>Entity Class: <v>%s", coll.getEntityClass().getName());
|
msg("<k>Entity Class: <v>%s", coll.getEntityClass().getName());
|
||||||
msg("<k>Plugin: <v>%s", coll.getPlugin().getDescription().getFullName());
|
msg("<k>Plugin: <v>%s", coll.getPlugin().getDescription().getFullName());
|
||||||
msg("<k>Database: <v>%s", coll.getDb().getName());
|
msg("<k>Database: <v>%s", coll.getDb().getDbName());
|
||||||
msg("<k>Driver: <v>%s", coll.getDriver().getName());
|
msg("<k>Driver: <v>%s", coll.getDb().getDriverName());
|
||||||
|
|
||||||
int limit;
|
int limit;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.massivecraft.massivecore.store;
|
package com.massivecraft.massivecore.store;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -44,6 +45,17 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
public static Map<String, Coll<?>> getMap() { return umap; }
|
public static Map<String, Coll<?>> getMap() { return umap; }
|
||||||
public static Set<String> getNames() { return unames; }
|
public static Set<String> getNames() { return unames; }
|
||||||
public static Collection<Coll<?>> getInstances() { return uinstances; }
|
public static Collection<Coll<?>> getInstances() { return uinstances; }
|
||||||
|
public static Collection<SenderColl<?>> getSenderInstances()
|
||||||
|
{
|
||||||
|
List<SenderColl<?>> ret = new ArrayList<SenderColl<?>>();
|
||||||
|
for (Coll<?> coll : getInstances())
|
||||||
|
{
|
||||||
|
if ( ! (coll instanceof SenderColl)) continue;
|
||||||
|
SenderColl<?> senderColl = (SenderColl<?>)coll;
|
||||||
|
ret.add(senderColl);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// WHAT DO WE HANDLE?
|
// WHAT DO WE HANDLE?
|
||||||
@ -81,7 +93,6 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
|
|
||||||
protected Db db;
|
protected Db db;
|
||||||
@Override public Db getDb() { return this.db; }
|
@Override public Db getDb() { return this.db; }
|
||||||
@Override public Driver getDriver() { return this.db.getDriver(); }
|
|
||||||
|
|
||||||
protected Object collDriverObject;
|
protected Object collDriverObject;
|
||||||
@Override public Object getCollDriverObject() { return this.collDriverObject; }
|
@Override public Object getCollDriverObject() { return this.collDriverObject; }
|
||||||
@ -94,8 +105,6 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
protected Map<String, E> id2entity;
|
protected Map<String, E> id2entity;
|
||||||
protected Map<E, String> entity2id;
|
protected Map<E, String> entity2id;
|
||||||
|
|
||||||
@Override public Collection<String> getIds() { return Collections.unmodifiableCollection(this.id2entity.keySet()); }
|
|
||||||
|
|
||||||
@Override public Map<String, E> getId2entity() { return Collections.unmodifiableMap(this.id2entity); }
|
@Override public Map<String, E> getId2entity() { return Collections.unmodifiableMap(this.id2entity); }
|
||||||
@Override
|
@Override
|
||||||
public E get(Object oid)
|
public E get(Object oid)
|
||||||
@ -107,18 +116,18 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
{
|
{
|
||||||
return this.get(oid, creative, true);
|
return this.get(oid, creative, true);
|
||||||
}
|
}
|
||||||
protected E get(Object oid, boolean creative, boolean noteChange)
|
protected E get(Object oid, boolean creative, boolean noteModification)
|
||||||
{
|
{
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
if (id == null) return null;
|
if (id == null) return null;
|
||||||
E ret = this.id2entity.get(id);
|
E ret = this.id2entity.get(id);
|
||||||
if (ret != null) return ret;
|
if (ret != null) return ret;
|
||||||
if ( ! creative) return null;
|
if ( ! creative) return null;
|
||||||
return this.create(id, noteChange);
|
return this.create(id, noteModification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Collection<String> getIdsLoaded() { return Collections.unmodifiableCollection(this.id2entity.keySet()); }
|
@Override public Collection<String> getIds() { return Collections.unmodifiableCollection(this.id2entity.keySet()); }
|
||||||
@Override public Collection<String> getIdsRemote() { return this.getDb().getDriver().getIds(this); }
|
@Override public Collection<String> getIdsRemote() { return this.getDb().getIds(this); }
|
||||||
@Override
|
@Override
|
||||||
public boolean containsId(Object oid)
|
public boolean containsId(Object oid)
|
||||||
{
|
{
|
||||||
@ -270,10 +279,10 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
return this.create(oid, true);
|
return this.create(oid, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized E create(Object oid, boolean noteChange)
|
public synchronized E create(Object oid, boolean noteModification)
|
||||||
{
|
{
|
||||||
E entity = this.createNewInstance();
|
E entity = this.createNewInstance();
|
||||||
if (this.attach(entity, oid, noteChange) == null) return null;
|
if (this.attach(entity, oid, noteModification) == null) return null;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +303,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
protected synchronized String attach(E entity, Object oid, boolean noteChange)
|
protected synchronized String attach(E entity, Object oid, boolean noteModification)
|
||||||
{
|
{
|
||||||
// Check entity
|
// Check entity
|
||||||
if (entity == null) return null;
|
if (entity == null) return null;
|
||||||
@ -327,11 +336,10 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
this.id2entity.put(id, entity);
|
this.id2entity.put(id, entity);
|
||||||
this.entity2id.put(entity, id);
|
this.entity2id.put(entity, id);
|
||||||
|
|
||||||
// Make note of the change
|
// Identify Modification
|
||||||
if (noteChange)
|
if (noteModification)
|
||||||
{
|
{
|
||||||
this.localAttachIds.add(id);
|
this.identifiedModifications.put(id, Modification.LOCAL_ATTACH);
|
||||||
this.changedIds.add(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
@ -383,9 +391,8 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
// Remove @ local
|
// Remove @ local
|
||||||
this.removeAtLocal(id);
|
this.removeAtLocal(id);
|
||||||
|
|
||||||
// Identify the change
|
// Identify Modification
|
||||||
this.localDetachIds.add(id);
|
this.identifiedModifications.put(id, Modification.LOCAL_DETACH);
|
||||||
this.changedIds.add(id);
|
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
this.postDetach(entity, id);
|
this.postDetach(entity, id);
|
||||||
@ -428,21 +435,16 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// IDENTIFIED CHANGES
|
// IDENTIFIED MODIFICATIONS
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
protected Set<String> localAttachIds;
|
protected Map<String, Modification> identifiedModifications;
|
||||||
protected Set<String> localDetachIds;
|
|
||||||
protected Set<String> changedIds;
|
|
||||||
|
|
||||||
protected synchronized void clearIdentifiedChanges(Object oid)
|
protected void removeIdentifiedModification(Object oid)
|
||||||
{
|
{
|
||||||
if (oid == null) throw new NullPointerException("oid");
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
|
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
this.localAttachIds.remove(id);
|
this.identifiedModifications.remove(id);
|
||||||
this.localDetachIds.remove(id);
|
|
||||||
this.changedIds.remove(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
@ -463,7 +465,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
this.lastDefault.remove(id);
|
this.lastDefault.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log database syncronization for display in the "/massivecore mstore stats" command.
|
// Log database synchronization for display in the "/massivecore mstore stats" command.
|
||||||
private Map<String, Long> id2out = new TreeMap<String, Long>();
|
private Map<String, Long> id2out = new TreeMap<String, Long>();
|
||||||
private Map<String, Long> id2in = new TreeMap<String, Long>();
|
private Map<String, Long> id2in = new TreeMap<String, Long>();
|
||||||
|
|
||||||
@ -494,11 +496,11 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
@Override
|
@Override
|
||||||
public synchronized E removeAtLocal(Object oid)
|
public synchronized E removeAtLocal(Object oid)
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
if (oid == null) throw new NullPointerException("oid");
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
|
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
this.clearIdentifiedChanges(id);
|
this.removeIdentifiedModification(id);
|
||||||
this.clearSynclog(id);
|
this.clearSynclog(id);
|
||||||
|
|
||||||
E entity = this.id2entity.remove(id);
|
E entity = this.id2entity.remove(id);
|
||||||
@ -519,24 +521,24 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
@Override
|
@Override
|
||||||
public synchronized void removeAtRemote(Object oid)
|
public synchronized void removeAtRemote(Object oid)
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
if (oid == null) throw new NullPointerException("oid");
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
|
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
this.clearIdentifiedChanges(id);
|
this.removeIdentifiedModification(id);
|
||||||
this.clearSynclog(id);
|
this.clearSynclog(id);
|
||||||
|
|
||||||
this.getDb().getDriver().delete(this, id);
|
this.getDb().delete(this, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void saveToRemote(Object oid)
|
public synchronized void saveToRemote(Object oid)
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
if (oid == null) throw new NullPointerException("oid");
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
|
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
this.clearIdentifiedChanges(id);
|
this.removeIdentifiedModification(id);
|
||||||
this.clearSynclog(id);
|
this.clearSynclog(id);
|
||||||
|
|
||||||
E entity = this.id2entity.get(id);
|
E entity = this.id2entity.get(id);
|
||||||
@ -547,31 +549,32 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
|
|
||||||
if (this.isDefault(entity) && isCustomDataDefault(entity))
|
if (this.isDefault(entity) && isCustomDataDefault(entity))
|
||||||
{
|
{
|
||||||
this.db.getDriver().delete(this, id);
|
this.getDb().delete(this, id);
|
||||||
this.lastDefault.add(id);
|
this.lastDefault.add(id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Long mtime = this.db.getDriver().save(this, id, raw);
|
long mtime = this.getDb().save(this, id, raw);
|
||||||
if (mtime == null) return; // This fail should not happen often. We could handle it better though.
|
if (mtime == 0) return; // This fail should not happen often. We could handle it better though.
|
||||||
this.lastMtime.put(id, mtime);
|
this.lastMtime.put(id, mtime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public synchronized void loadFromRemote(Object oid, Entry<JsonElement, Long> entry, boolean entrySupplied)
|
public synchronized void loadFromRemote(Object oid, Entry<JsonElement, Long> remoteEntry)
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
if (oid == null) throw new NullPointerException("oid");
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
this.clearIdentifiedChanges(id);
|
this.removeIdentifiedModification(id);
|
||||||
|
|
||||||
if ( ! entrySupplied)
|
if (remoteEntry == null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
entry = this.getDriver().load(this, id);
|
remoteEntry = this.getDb().load(this, id);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -580,13 +583,20 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry == null)
|
Long mtime = remoteEntry.getValue();
|
||||||
|
if (mtime == null)
|
||||||
{
|
{
|
||||||
logLoadError(id, "MStore driver could not load data entry. The file might not be readable or simply not exist.");
|
logLoadError(id, "Last modification time (mtime) was null. The file might not be readable or simply not exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonElement raw = entry.getKey();
|
if (mtime == 0)
|
||||||
|
{
|
||||||
|
logLoadError(id, "Last modification time (mtime) was 0. The file might not be readable or simply not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonElement raw = remoteEntry.getKey();
|
||||||
if (raw == null)
|
if (raw == null)
|
||||||
{
|
{
|
||||||
logLoadError(id, "Raw data was null. Is the file completely empty?");
|
logLoadError(id, "Raw data was null. Is the file completely empty?");
|
||||||
@ -598,13 +608,6 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long mtime = entry.getValue();
|
|
||||||
if (mtime == null)
|
|
||||||
{
|
|
||||||
logLoadError(id, "Last modification time (mtime) was null.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate temp but handle raw cases.
|
// Calculate temp but handle raw cases.
|
||||||
E temp = null;
|
E temp = null;
|
||||||
if (this.getEntityClass().isAssignableFrom(JsonObject.class))
|
if (this.getEntityClass().isAssignableFrom(JsonObject.class))
|
||||||
@ -651,61 +654,63 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModificationState examineId(Object oid)
|
public Modification examineId(Object oid)
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
return this.examineId(id, null, false);
|
|
||||||
|
return this.examineId(id, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModificationState examineId(Object oid, Long remoteMtime)
|
public Modification examineId(Object oid, Long remoteMtime)
|
||||||
{
|
|
||||||
String id = this.fixId(oid);
|
|
||||||
return this.examineId(id, remoteMtime, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ModificationState examineId(Object oid, Long remoteMtime, boolean remoteMtimeSupplied)
|
|
||||||
{
|
{
|
||||||
|
// Fix Id
|
||||||
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
if (this.localDetachIds.contains(id)) return ModificationState.LOCAL_DETACH;
|
// Local Attach and Detach has the top priority.
|
||||||
if (this.localAttachIds.contains(id)) return ModificationState.LOCAL_ATTACH;
|
// Otherwise newly attached entities would be removed thinking it was a remote detach.
|
||||||
|
// Otherwise newly detached entities would be loaded thinking it was a remote attach.
|
||||||
|
Modification ret = this.identifiedModifications.get(id);
|
||||||
|
if (ret == Modification.LOCAL_ATTACH || ret == Modification.LOCAL_DETACH) return ret;
|
||||||
|
|
||||||
E localEntity = this.id2entity.get(id);
|
E localEntity = this.id2entity.get(id);
|
||||||
if ( ! remoteMtimeSupplied)
|
if (remoteMtime == null)
|
||||||
{
|
{
|
||||||
remoteMtime = this.getDriver().getMtime(this, id);
|
remoteMtime = this.getDb().getMtime(this, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean existsLocal = (localEntity != null);
|
boolean existsLocal = (localEntity != null);
|
||||||
boolean existsRemote = (remoteMtime != null);
|
boolean existsRemote = (remoteMtime != 0);
|
||||||
|
|
||||||
if ( ! existsLocal && ! existsRemote) return ModificationState.UNKNOWN;
|
if ( ! existsLocal && ! existsRemote) return Modification.UNKNOWN;
|
||||||
|
|
||||||
if (existsLocal && existsRemote)
|
if (existsLocal && existsRemote)
|
||||||
{
|
{
|
||||||
Long lastMtime = this.lastMtime.get(id);
|
Long lastMtime = this.lastMtime.get(id);
|
||||||
if (remoteMtime.equals(lastMtime) == false) return ModificationState.REMOTE_ALTER;
|
if (remoteMtime.equals(lastMtime) == false) return Modification.REMOTE_ALTER;
|
||||||
|
|
||||||
if (this.examineHasLocalAlter(id, localEntity)) return ModificationState.LOCAL_ALTER;
|
if (this.examineHasLocalAlter(id, localEntity)) return Modification.LOCAL_ALTER;
|
||||||
}
|
}
|
||||||
else if (existsLocal)
|
else if (existsLocal)
|
||||||
{
|
{
|
||||||
if (this.lastDefault.contains(id))
|
if (this.lastDefault.contains(id))
|
||||||
{
|
{
|
||||||
if (this.examineHasLocalAlter(id, localEntity)) return ModificationState.LOCAL_ALTER;
|
if (this.examineHasLocalAlter(id, localEntity)) return Modification.LOCAL_ALTER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return ModificationState.REMOTE_DETACH;
|
return Modification.REMOTE_DETACH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (existsRemote)
|
else if (existsRemote)
|
||||||
{
|
{
|
||||||
return ModificationState.REMOTE_ATTACH;
|
return Modification.REMOTE_ATTACH;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModificationState.NONE;
|
return Modification.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean examineHasLocalAlter(String id, E entity)
|
protected boolean examineHasLocalAlter(String id, E entity)
|
||||||
@ -730,15 +735,36 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModificationState syncId(Object oid)
|
public Modification syncId(Object oid)
|
||||||
{
|
{
|
||||||
|
return this.syncId(oid, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Modification syncId(Object oid, Modification modification)
|
||||||
|
{
|
||||||
|
return this.syncId(oid, modification, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Modification syncId(Object oid, Modification modification, Entry<JsonElement, Long> remoteEntry)
|
||||||
|
{
|
||||||
|
// Fix Id
|
||||||
|
if (oid == null) throw new NullPointerException("oid");
|
||||||
String id = this.fixId(oid);
|
String id = this.fixId(oid);
|
||||||
|
|
||||||
ModificationState mstate = this.examineId(id);
|
if (modification == null || modification == Modification.UNKNOWN)
|
||||||
|
{
|
||||||
|
Long remoteMtime = null;
|
||||||
|
if (remoteEntry != null) remoteMtime = remoteEntry.getValue();
|
||||||
|
|
||||||
|
modification = this.examineId(id, remoteMtime);
|
||||||
|
}
|
||||||
|
|
||||||
//mplugin.log("syncId: It seems", id, "has state", mstate);
|
// DEBUG
|
||||||
|
// MassiveCore.get().log(Txt.parse("<k>Coll: <v>%s <k>Entity: <v>%s <k>Modification: <v>%s", this.getName(), id, modification));
|
||||||
|
|
||||||
switch (mstate)
|
switch (modification)
|
||||||
{
|
{
|
||||||
case LOCAL_ALTER:
|
case LOCAL_ALTER:
|
||||||
case LOCAL_ATTACH:
|
case LOCAL_ATTACH:
|
||||||
@ -759,7 +785,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
break;
|
break;
|
||||||
case REMOTE_ALTER:
|
case REMOTE_ALTER:
|
||||||
case REMOTE_ATTACH:
|
case REMOTE_ATTACH:
|
||||||
this.loadFromRemote(id, null, false);
|
this.loadFromRemote(id, remoteEntry);
|
||||||
if (this.inited())
|
if (this.inited())
|
||||||
{
|
{
|
||||||
this.addSyncCount(TOTAL, true);
|
this.addSyncCount(TOTAL, true);
|
||||||
@ -775,47 +801,18 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.clearIdentifiedChanges(id);
|
this.removeIdentifiedModification(id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mstate;
|
return modification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncSuspects()
|
public void identifyModifications()
|
||||||
{
|
{
|
||||||
/*if (MassiveCore.get().doderp)
|
// Get remote id2mtime snapshot
|
||||||
{
|
Map<String, Long> id2RemoteMtime = this.getDb().getId2mtime(this);
|
||||||
if (this.changedIds.size() > 0)
|
|
||||||
{
|
|
||||||
System.out.println("Coll " + this.getName() + " had suspects " + Txt.implode(this.changedIds, " "));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
for (String id : this.changedIds)
|
|
||||||
{
|
|
||||||
this.syncId(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void syncAll()
|
|
||||||
{
|
|
||||||
// Find all ids
|
|
||||||
Set<String> allids = new HashSet<String>(this.id2entity.keySet());
|
|
||||||
allids.addAll(this.getDriver().getIds(this));
|
|
||||||
for (String id : allids)
|
|
||||||
{
|
|
||||||
this.syncId(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void findSuspects()
|
|
||||||
{
|
|
||||||
// Get remote id and mtime snapshot
|
|
||||||
Map<String, Long> id2RemoteMtime = this.getDb().getDriver().getId2mtime(this);
|
|
||||||
|
|
||||||
// Compile a list of all ids (both remote and local)
|
// Compile a list of all ids (both remote and local)
|
||||||
Set<String> allids = new HashSet<String>();
|
Set<String> allids = new HashSet<String>();
|
||||||
@ -826,27 +823,45 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
for (String id : allids)
|
for (String id : allids)
|
||||||
{
|
{
|
||||||
Long remoteMtime = id2RemoteMtime.get(id);
|
Long remoteMtime = id2RemoteMtime.get(id);
|
||||||
ModificationState state = this.examineId(id, remoteMtime);
|
if (remoteMtime == null) remoteMtime = 0L;
|
||||||
//mplugin.log("findSuspects: It seems", id, "has state", state);
|
|
||||||
if (state.isModified())
|
Modification modification = this.examineId(id, remoteMtime);
|
||||||
|
if (modification.isModified())
|
||||||
{
|
{
|
||||||
//System.out.println("It seems "+id+" has state "+state);
|
this.identifiedModifications.put(id, modification);
|
||||||
this.changedIds.add(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncIdentified()
|
||||||
|
{
|
||||||
|
for (Entry<String, Modification> entry : this.identifiedModifications.entrySet())
|
||||||
|
{
|
||||||
|
String id = entry.getKey();
|
||||||
|
Modification modification = entry.getValue();
|
||||||
|
this.syncId(id, modification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncAll()
|
||||||
|
{
|
||||||
|
this.identifyModifications();
|
||||||
|
this.syncIdentified();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initLoadAllFromRemote()
|
public void initLoadAllFromRemote()
|
||||||
{
|
{
|
||||||
Map<String, Entry<JsonElement, Long>> idToEntryMap = this.getDb().getDriver().loadAll(this);
|
Map<String, Entry<JsonElement, Long>> idToEntryMap = this.getDb().loadAll(this);
|
||||||
if (idToEntryMap == null) return;
|
if (idToEntryMap == null) return;
|
||||||
|
|
||||||
for (Entry<String, Entry<JsonElement, Long>> idToEntry : idToEntryMap.entrySet())
|
for (Entry<String, Entry<JsonElement, Long>> idToEntry : idToEntryMap.entrySet())
|
||||||
{
|
{
|
||||||
String id = idToEntry.getKey();
|
String id = idToEntry.getKey();
|
||||||
Entry<JsonElement, Long> entry = idToEntry.getValue();
|
Entry<JsonElement, Long> remoteEntry = idToEntry.getValue();
|
||||||
loadFromRemote(id, entry, true);
|
loadFromRemote(id, remoteEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,7 +874,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
@Override
|
@Override
|
||||||
public void onTick()
|
public void onTick()
|
||||||
{
|
{
|
||||||
this.syncSuspects();
|
this.syncIdentified();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
@ -889,7 +904,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
// SUPPORTING SYSTEM
|
// SUPPORTING SYSTEM
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.collDriverObject = db.getCollDriverObject(this);
|
this.collDriverObject = db.createCollDriverObject(this);
|
||||||
|
|
||||||
// STORAGE
|
// STORAGE
|
||||||
if (entityComparator == null && !Comparable.class.isAssignableFrom(entityClass))
|
if (entityComparator == null && !Comparable.class.isAssignableFrom(entityClass))
|
||||||
@ -900,10 +915,8 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
this.id2entity = new ConcurrentSkipListMap<String, E>(idComparator);
|
this.id2entity = new ConcurrentSkipListMap<String, E>(idComparator);
|
||||||
this.entity2id = new ConcurrentSkipListMap<E, String>(entityComparator);
|
this.entity2id = new ConcurrentSkipListMap<E, String>(entityComparator);
|
||||||
|
|
||||||
// IDENTIFIED CHANGES
|
// IDENTIFIED MODIFICATIONS
|
||||||
this.localAttachIds = new ConcurrentSkipListSet<String>(idComparator);
|
this.identifiedModifications = new ConcurrentSkipListMap<String, Modification>(idComparator);
|
||||||
this.localDetachIds = new ConcurrentSkipListSet<String>(idComparator);
|
|
||||||
this.changedIds = new ConcurrentSkipListSet<String>(idComparator);
|
|
||||||
|
|
||||||
// SYNCLOG
|
// SYNCLOG
|
||||||
this.lastMtime = new ConcurrentSkipListMap<String, Long>(idComparator);
|
this.lastMtime = new ConcurrentSkipListMap<String, Long>(idComparator);
|
||||||
@ -941,7 +954,7 @@ public class Coll<E> implements CollInterface<E>
|
|||||||
@Override
|
@Override
|
||||||
public void deinit()
|
public void deinit()
|
||||||
{
|
{
|
||||||
if (!this.inited()) return;
|
if ( ! this.inited()) return;
|
||||||
|
|
||||||
// TODO: Save outwards only? We may want to avoid loads at this stage...
|
// TODO: Save outwards only? We may want to avoid loads at this stage...
|
||||||
this.syncAll();
|
this.syncAll();
|
||||||
|
@ -27,7 +27,6 @@ public interface CollInterface<E>
|
|||||||
public Plugin getPlugin();
|
public Plugin getPlugin();
|
||||||
|
|
||||||
public Db getDb();
|
public Db getDb();
|
||||||
public Driver getDriver();
|
|
||||||
public Object getCollDriverObject();
|
public Object getCollDriverObject();
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
@ -36,9 +35,8 @@ public interface CollInterface<E>
|
|||||||
public Map<String, E> getId2entity();
|
public Map<String, E> getId2entity();
|
||||||
public E get(Object oid);
|
public E get(Object oid);
|
||||||
public E get(Object oid, boolean creative);
|
public E get(Object oid, boolean creative);
|
||||||
public Collection<String> getIds(); // All ideas we know of whether they are loaded or not
|
public Collection<String> getIds();
|
||||||
public Collection<String> getIdsRemote(); // All remote ids loaded sync via driver
|
public Collection<String> getIdsRemote();
|
||||||
public Collection<String> getIdsLoaded(); // All locally loaded ids
|
|
||||||
public boolean containsId(Object oid);
|
public boolean containsId(Object oid);
|
||||||
|
|
||||||
public Map<E, String> getEntity2id();
|
public Map<E, String> getEntity2id();
|
||||||
@ -130,19 +128,21 @@ public interface CollInterface<E>
|
|||||||
public E removeAtLocal(Object oid);
|
public E removeAtLocal(Object oid);
|
||||||
public void removeAtRemote(Object oid);
|
public void removeAtRemote(Object oid);
|
||||||
public void saveToRemote(Object oid);
|
public void saveToRemote(Object oid);
|
||||||
public void loadFromRemote(Object oid, Entry<JsonElement, Long> entry, boolean entrySupplied);
|
public void loadFromRemote(Object oid, Entry<JsonElement, Long> remoteEntry);
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// SYNC EXAMINE AND DO
|
// SYNC EXAMINE AND DO
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public ModificationState examineId(Object oid);
|
public Modification examineId(Object oid);
|
||||||
public ModificationState examineId(Object oid, Long remoteMtime);
|
public Modification examineId(Object oid, Long remoteMtime);
|
||||||
|
|
||||||
public ModificationState syncId(Object oid);
|
public Modification syncId(Object oid);
|
||||||
public void syncSuspects();
|
public Modification syncId(Object oid, Modification modificationState);
|
||||||
|
public Modification syncId(Object oid, Modification modificationState, Entry<JsonElement, Long> remoteEntry);
|
||||||
|
public void syncIdentified();
|
||||||
public void syncAll();
|
public void syncAll();
|
||||||
public void findSuspects();
|
public void identifyModifications();
|
||||||
public void initLoadAllFromRemote();
|
public void initLoadAllFromRemote();
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
@ -1,16 +1,44 @@
|
|||||||
package com.massivecraft.massivecore.store;
|
package com.massivecraft.massivecore.store;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||||
|
|
||||||
public interface Db
|
public interface Db
|
||||||
{
|
{
|
||||||
public String getName();
|
// -------------------------------------------- //
|
||||||
|
// FIELDS
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public boolean drop();
|
// Returns the name of the database.
|
||||||
|
public String getDbName();
|
||||||
public Set<String> getCollnames();
|
|
||||||
|
|
||||||
|
// Returns the driver running this database.
|
||||||
public Driver getDriver();
|
public Driver getDriver();
|
||||||
|
|
||||||
public Object getCollDriverObject(Coll<?> coll);
|
// Creates a new collection driver object.
|
||||||
|
// This object will be stored inside the Coll.
|
||||||
|
public Object createCollDriverObject(Coll<?> coll);
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// DRIVER
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public String getDriverName();
|
||||||
|
public Db getDb(String uri);
|
||||||
|
public boolean dropDb();
|
||||||
|
public Set<String> getCollnames();
|
||||||
|
public boolean renameColl(String from, String to);
|
||||||
|
public boolean containsId(Coll<?> coll, String id);
|
||||||
|
public long getMtime(Coll<?> coll, String id);
|
||||||
|
public Collection<String> getIds(Coll<?> coll);
|
||||||
|
public Map<String, Long> getId2mtime(Coll<?> coll);
|
||||||
|
public Entry<JsonElement, Long> load(Coll<?> coll, String id);
|
||||||
|
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll);
|
||||||
|
public long save(Coll<?> coll, String id, JsonElement data);
|
||||||
|
public void delete(Coll<?> coll, String id);
|
||||||
|
|
||||||
}
|
}
|
@ -1,12 +1,80 @@
|
|||||||
package com.massivecraft.massivecore.store;
|
package com.massivecraft.massivecore.store;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||||
|
|
||||||
public abstract class DbAbstract implements Db
|
public abstract class DbAbstract implements Db
|
||||||
{
|
{
|
||||||
@Override
|
// -------------------------------------------- //
|
||||||
|
// DRIVER
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public String getDriverName()
|
||||||
|
{
|
||||||
|
return this.getDriver().getDriverName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Db getDb(String uri)
|
||||||
|
{
|
||||||
|
return this.getDriver().getDb(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dropDb()
|
||||||
|
{
|
||||||
|
return this.getDriver().dropDb(this);
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getCollnames()
|
public Set<String> getCollnames()
|
||||||
{
|
{
|
||||||
return this.getDriver().getCollnames(this);
|
return this.getDriver().getCollnames(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean renameColl(String from, String to)
|
||||||
|
{
|
||||||
|
return this.getDriver().renameColl(this, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsId(Coll<?> coll, String id)
|
||||||
|
{
|
||||||
|
return this.getDriver().containsId(coll, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMtime(Coll<?> coll, String id)
|
||||||
|
{
|
||||||
|
return this.getDriver().getMtime(coll, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<String> getIds(Coll<?> coll)
|
||||||
|
{
|
||||||
|
return this.getDriver().getIds(coll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Long> getId2mtime(Coll<?> coll)
|
||||||
|
{
|
||||||
|
return this.getDriver().getId2mtime(coll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry<JsonElement, Long> load(Coll<?> coll, String id)
|
||||||
|
{
|
||||||
|
return this.getDriver().load(coll, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll)
|
||||||
|
{
|
||||||
|
return this.getDriver().loadAll(coll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long save(Coll<?> coll, String id, JsonElement data)
|
||||||
|
{
|
||||||
|
return this.getDriver().save(coll, id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Coll<?> coll, String id)
|
||||||
|
{
|
||||||
|
this.getDriver().delete(coll, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,56 +2,41 @@ package com.massivecraft.massivecore.store;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import com.massivecraft.massivecore.util.DiscUtil;
|
|
||||||
|
|
||||||
public class DbFlatfile extends DbAbstract
|
public class DbFlatfile extends DbAbstract
|
||||||
{
|
{
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// FIELDS
|
// FIELDS
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public File dir;
|
public File directory;
|
||||||
|
|
||||||
protected DriverFlatfile driver;
|
protected DriverFlatfile driver;
|
||||||
@Override public DriverFlatfile getDriver() { return driver; }
|
@Override public DriverFlatfile getDriver() { return driver; }
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// CONSTRUCTORS
|
// CONSTRUCT
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public DbFlatfile(DriverFlatfile driver, File folder)
|
public DbFlatfile(DriverFlatfile driver, File directory)
|
||||||
{
|
{
|
||||||
this.driver = driver;
|
this.driver = driver;
|
||||||
this.dir = folder;
|
this.directory = directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// IMPLEMENTATION
|
// OVERRIDE
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName()
|
public String getDbName()
|
||||||
{
|
{
|
||||||
return dir.getAbsolutePath();
|
return directory.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean drop()
|
public Object createCollDriverObject(Coll<?> coll)
|
||||||
{
|
{
|
||||||
try
|
return new File(directory, coll.getName());
|
||||||
{
|
|
||||||
return DiscUtil.deleteRecursive(this.dir);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getCollDriverObject(Coll<?> coll)
|
|
||||||
{
|
|
||||||
return new File(dir, coll.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,32 +24,19 @@ public class DbMongo extends DbAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// IMPLEMENTATION
|
// OVERRIDE
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName()
|
public String getDbName()
|
||||||
{
|
{
|
||||||
return db.getName();
|
return db.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean drop()
|
public Object createCollDriverObject(Coll<?> coll)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.db.dropDatabase();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getCollDriverObject(Coll<?> coll)
|
|
||||||
{
|
{
|
||||||
return db.getCollection(coll.getName());
|
return db.getCollection(coll.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,15 @@ import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
|||||||
public interface Driver
|
public interface Driver
|
||||||
{
|
{
|
||||||
// Returns the name of the driver.
|
// Returns the name of the driver.
|
||||||
public String getName();
|
public String getDriverName();
|
||||||
|
|
||||||
// Get a database instance from the driver
|
// Get a database instance from the driver
|
||||||
public Db getDb(String uri);
|
public Db getDb(String uri);
|
||||||
|
|
||||||
// What collections are in the database?
|
// This will delete the whole database and all collections therein.
|
||||||
|
public boolean dropDb(Db db);
|
||||||
|
|
||||||
|
// What collections are in the database?
|
||||||
public Set<String> getCollnames(Db db);
|
public Set<String> getCollnames(Db db);
|
||||||
|
|
||||||
// Rename a collection
|
// Rename a collection
|
||||||
@ -25,7 +28,10 @@ public interface Driver
|
|||||||
public boolean containsId(Coll<?> coll, String id);
|
public boolean containsId(Coll<?> coll, String id);
|
||||||
|
|
||||||
// When was X last altered?
|
// When was X last altered?
|
||||||
public Long getMtime(Coll<?> coll, String id);
|
// return == null will never happen.
|
||||||
|
// return != 0 means X exists and return is when it last was altered.
|
||||||
|
// return == 0 means X does not exist in the database.
|
||||||
|
public long getMtime(Coll<?> coll, String id);
|
||||||
|
|
||||||
// What ids are in the collection?
|
// What ids are in the collection?
|
||||||
public Collection<String> getIds(Coll<?> coll);
|
public Collection<String> getIds(Coll<?> coll);
|
||||||
@ -34,15 +40,20 @@ public interface Driver
|
|||||||
public Map<String, Long> getId2mtime(Coll<?> coll);
|
public Map<String, Long> getId2mtime(Coll<?> coll);
|
||||||
|
|
||||||
// Load the raw data for X. The second part of the entry is the remote mtime at the load.
|
// Load the raw data for X. The second part of the entry is the remote mtime at the load.
|
||||||
|
// return == null will never happen.
|
||||||
|
// return.getKey() == null || return.getValue() == 0 means something failed.
|
||||||
public Entry<JsonElement, Long> load(Coll<?> coll, String id);
|
public Entry<JsonElement, Long> load(Coll<?> coll, String id);
|
||||||
|
|
||||||
// Load all database content at once
|
// Load all database content at once
|
||||||
|
// NOTE: This method is assumed to be based on the one above.
|
||||||
|
// NOTE: Values where JsonElement == null and Long == 0 may occur.
|
||||||
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll);
|
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll);
|
||||||
|
|
||||||
// Save raw data as X
|
// Save raw data as X
|
||||||
// Return value is the new mtime (we caused the change).
|
// Return value is the new mtime (we caused the change).
|
||||||
// If the mtime is null something failed.
|
// return == null will never happen.
|
||||||
public Long save(Coll<?> coll, String id, JsonElement data);
|
// return == 0 means something failed. Usually failures are not catched, though. System.currentTimeMillis() is returned most of the time.
|
||||||
|
public long save(Coll<?> coll, String id, JsonElement data);
|
||||||
|
|
||||||
// Delete X
|
// Delete X
|
||||||
public void delete(Coll<?> coll, String id);
|
public void delete(Coll<?> coll, String id);
|
||||||
|
@ -7,7 +7,7 @@ public abstract class DriverAbstract implements Driver
|
|||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
@Override public String getName() { return this.name; }
|
@Override public String getDriverName() { return this.name; }
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// CONSTRUCT
|
// CONSTRUCT
|
||||||
|
@ -41,9 +41,25 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
public Db getDb(String uri)
|
public Db getDb(String uri)
|
||||||
{
|
{
|
||||||
// "flatfile://" is 8+3=11 chars
|
// "flatfile://" is 8+3=11 chars
|
||||||
File folder = new File(uri.substring(NAME.length() + 3));
|
File directory = new File(uri.substring(NAME.length() + 3));
|
||||||
folder.mkdirs();
|
directory.mkdirs();
|
||||||
return new DbFlatfile(this, folder);
|
return new DbFlatfile(this, directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dropDb(Db db)
|
||||||
|
{
|
||||||
|
if ( ! (db instanceof DbFlatfile)) throw new IllegalArgumentException("db");
|
||||||
|
DbFlatfile dbFlatfile = (DbFlatfile)db;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DiscUtil.deleteRecursive(dbFlatfile.directory);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -51,10 +67,10 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
{
|
{
|
||||||
Set<String> ret = new LinkedHashSet<String>();
|
Set<String> ret = new LinkedHashSet<String>();
|
||||||
|
|
||||||
for (File f : ((DbFlatfile)db).dir.listFiles())
|
for (File file : ((DbFlatfile)db).directory.listFiles())
|
||||||
{
|
{
|
||||||
if ( ! f.isDirectory()) continue;
|
if ( ! file.isDirectory()) continue;
|
||||||
ret.add(f.getName());
|
ret.add(file.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -63,7 +79,7 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
@Override
|
@Override
|
||||||
public boolean renameColl(Db db, String from, String to)
|
public boolean renameColl(Db db, String from, String to)
|
||||||
{
|
{
|
||||||
File dir = ((DbFlatfile)db).dir;
|
File dir = ((DbFlatfile)db).directory;
|
||||||
File fileFrom = new File(dir, from);
|
File fileFrom = new File(dir, from);
|
||||||
File fileTo = new File(dir, to);
|
File fileTo = new File(dir, to);
|
||||||
return fileFrom.renameTo(fileTo);
|
return fileFrom.renameTo(fileTo);
|
||||||
@ -76,10 +92,10 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getMtime(Coll<?> coll, String id)
|
public long getMtime(Coll<?> coll, String id)
|
||||||
{
|
{
|
||||||
File file = fileFromId(coll, id);
|
File file = fileFromId(coll, id);
|
||||||
if ( ! file.isFile()) return null;
|
if ( ! file.isFile()) return 0;
|
||||||
return file.lastModified();
|
return file.lastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +105,7 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
List<String> ret = new ArrayList<String>();
|
List<String> ret = new ArrayList<String>();
|
||||||
|
|
||||||
// Scan the collection folder for .json files
|
// Scan the collection folder for .json files
|
||||||
File collDir = getCollDir(coll);
|
File collDir = getDirectory(coll);
|
||||||
if ( ! collDir.isDirectory()) return ret;
|
if ( ! collDir.isDirectory()) return ret;
|
||||||
for (File file : collDir.listFiles(JsonFileFilter.get()))
|
for (File file : collDir.listFiles(JsonFileFilter.get()))
|
||||||
{
|
{
|
||||||
@ -105,15 +121,16 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
// Create Ret
|
// Create Ret
|
||||||
Map<String, Long> ret = new HashMap<String, Long>();
|
Map<String, Long> ret = new HashMap<String, Long>();
|
||||||
|
|
||||||
// Get collection directory
|
// Get Directory
|
||||||
File collDir = getCollDir(coll);
|
File directory = getDirectory(coll);
|
||||||
if (!collDir.isDirectory()) return ret;
|
if ( ! directory.isDirectory()) return ret;
|
||||||
|
|
||||||
// For each .json file
|
// For each .json file
|
||||||
for (File file : collDir.listFiles(JsonFileFilter.get()))
|
for (File file : directory.listFiles(JsonFileFilter.get()))
|
||||||
{
|
{
|
||||||
String id = idFromFile(file);
|
String id = idFromFile(file);
|
||||||
long mtime = file.lastModified();
|
long mtime = file.lastModified();
|
||||||
|
// TODO: Check is 0 here?
|
||||||
ret.put(id, mtime);
|
ret.put(id, mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,11 +147,8 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
|
|
||||||
public Entry<JsonElement, Long> loadFile(File file)
|
public Entry<JsonElement, Long> loadFile(File file)
|
||||||
{
|
{
|
||||||
Long mtime = file.lastModified();
|
long mtime = file.lastModified();
|
||||||
if (mtime == 0) return null;
|
|
||||||
|
|
||||||
JsonElement raw = loadFileJson(file);
|
JsonElement raw = loadFileJson(file);
|
||||||
if (raw == null) return null;
|
|
||||||
|
|
||||||
return new SimpleEntry<JsonElement, Long>(raw, mtime);
|
return new SimpleEntry<JsonElement, Long>(raw, mtime);
|
||||||
}
|
}
|
||||||
@ -153,15 +167,15 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll)
|
public Map<String, Entry<JsonElement, Long>> loadAll(Coll<?> coll)
|
||||||
{
|
{
|
||||||
// Declare Ret
|
// Create Ret
|
||||||
Map<String, Entry<JsonElement, Long>> ret = null;
|
Map<String, Entry<JsonElement, Long>> ret = null;
|
||||||
|
|
||||||
// Get collection directory
|
// Get Directory
|
||||||
File collDir = getCollDir(coll);
|
File directory = getDirectory(coll);
|
||||||
if ( ! collDir.isDirectory()) return ret;
|
if ( ! directory.isDirectory()) return ret;
|
||||||
|
|
||||||
// Find All
|
// Find All
|
||||||
File[] files = collDir.listFiles(JsonFileFilter.get());
|
File[] files = directory.listFiles(JsonFileFilter.get());
|
||||||
|
|
||||||
// Create Ret
|
// Create Ret
|
||||||
ret = new LinkedHashMap<String, Entry<JsonElement, Long>>(files.length);
|
ret = new LinkedHashMap<String, Entry<JsonElement, Long>>(files.length);
|
||||||
@ -174,6 +188,9 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
|
|
||||||
// Get Entry
|
// Get Entry
|
||||||
Entry<JsonElement, Long> entry = loadFile(file);
|
Entry<JsonElement, Long> entry = loadFile(file);
|
||||||
|
// NOTE: The entry can be a failed one with null and 0.
|
||||||
|
// NOTE: We add it anyways since it's an informative failure.
|
||||||
|
// NOTE: This is supported by our defined specification.
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
ret.put(id, entry);
|
ret.put(id, entry);
|
||||||
@ -184,11 +201,11 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long save(Coll<?> coll, String id, JsonElement data)
|
public long save(Coll<?> coll, String id, JsonElement data)
|
||||||
{
|
{
|
||||||
File file = fileFromId(coll, id);
|
File file = fileFromId(coll, id);
|
||||||
String content = coll.getGson().toJson(data);
|
String content = coll.getGson().toJson(data);
|
||||||
if (DiscUtil.writeCatch(file, content) == false) return null;
|
if (DiscUtil.writeCatch(file, content) == false) return 0;
|
||||||
return file.lastModified();
|
return file.lastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +220,7 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
// UTIL
|
// UTIL
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
public static File getCollDir(Coll<?> coll)
|
public static File getDirectory(Coll<?> coll)
|
||||||
{
|
{
|
||||||
return (File) coll.getCollDriverObject();
|
return (File) coll.getCollDriverObject();
|
||||||
}
|
}
|
||||||
@ -217,7 +234,7 @@ public class DriverFlatfile extends DriverAbstract
|
|||||||
|
|
||||||
public static File fileFromId(Coll<?> coll, String id)
|
public static File fileFromId(Coll<?> coll, String id)
|
||||||
{
|
{
|
||||||
File collDir = getCollDir(coll);
|
File collDir = getDirectory(coll);
|
||||||
File idFile = new File(collDir, id + DOTJSON);
|
File idFile = new File(collDir, id + DOTJSON);
|
||||||
return idFile;
|
return idFile;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,23 @@ public class DriverMongo extends DriverAbstract
|
|||||||
DB db = this.getDbInner(uri);
|
DB db = this.getDbInner(uri);
|
||||||
return new DbMongo(this, db);
|
return new DbMongo(this, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dropDb(Db db)
|
||||||
|
{
|
||||||
|
if ( ! (db instanceof DbMongo)) throw new IllegalArgumentException("db");
|
||||||
|
DbMongo dbMongo = (DbMongo)db;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dbMongo.db.dropDatabase();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getCollnames(Db db)
|
public Set<String> getCollnames(Db db)
|
||||||
@ -81,15 +98,17 @@ public class DriverMongo extends DriverAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getMtime(Coll<?> coll, String id)
|
public long getMtime(Coll<?> coll, String id)
|
||||||
{
|
{
|
||||||
DBCollection dbcoll = fixColl(coll);
|
DBCollection dbcoll = fixColl(coll);
|
||||||
|
|
||||||
BasicDBObject found = (BasicDBObject)dbcoll.findOne(new BasicDBObject(ID_FIELD, id), dboKeysMtime);
|
BasicDBObject found = (BasicDBObject)dbcoll.findOne(new BasicDBObject(ID_FIELD, id), dboKeysMtime);
|
||||||
if (found == null) return null;
|
if (found == null) return 0;
|
||||||
|
|
||||||
// In case there is no _mtime set we assume 0. Probably a manual database addition by the server owner.
|
// In case there is no _mtime set we assume 1337.
|
||||||
long mtime = found.getLong(MTIME_FIELD, 0);
|
// NOTE: We can not use 0 since that one is reserved for errors.
|
||||||
|
// Probably a manual database addition by the server owner.
|
||||||
|
long mtime = found.getLong(MTIME_FIELD, 1337L);
|
||||||
|
|
||||||
return mtime;
|
return mtime;
|
||||||
}
|
}
|
||||||
@ -105,7 +124,7 @@ public class DriverMongo extends DriverAbstract
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ret = new ArrayList<String>(cursor.count());
|
ret = new ArrayList<String>(cursor.count());
|
||||||
while(cursor.hasNext())
|
while (cursor.hasNext())
|
||||||
{
|
{
|
||||||
Object remoteId = cursor.next().get(ID_FIELD);
|
Object remoteId = cursor.next().get(ID_FIELD);
|
||||||
ret.add(remoteId.toString());
|
ret.add(remoteId.toString());
|
||||||
@ -130,13 +149,15 @@ public class DriverMongo extends DriverAbstract
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ret = new HashMap<String, Long>(cursor.count());
|
ret = new HashMap<String, Long>(cursor.count());
|
||||||
while(cursor.hasNext())
|
while (cursor.hasNext())
|
||||||
{
|
{
|
||||||
BasicDBObject raw = (BasicDBObject)cursor.next();
|
BasicDBObject raw = (BasicDBObject)cursor.next();
|
||||||
Object remoteId = raw.get(ID_FIELD);
|
Object remoteId = raw.get(ID_FIELD);
|
||||||
|
|
||||||
// In case there is no _mtime set we assume 0. Probably a manual database addition by the server owner.
|
// In case there is no _mtime set we assume 1337.
|
||||||
long mtime = raw.getLong(MTIME_FIELD, 0);
|
// NOTE: We can not use 0 since that one is reserved for errors.
|
||||||
|
// Probably a manual database addition by the server owner.
|
||||||
|
long mtime = raw.getLong(MTIME_FIELD, 1337L);
|
||||||
|
|
||||||
ret.put(remoteId.toString(), mtime);
|
ret.put(remoteId.toString(), mtime);
|
||||||
}
|
}
|
||||||
@ -159,13 +180,15 @@ public class DriverMongo extends DriverAbstract
|
|||||||
|
|
||||||
public Entry<JsonElement, Long> loadRaw(BasicDBObject raw)
|
public Entry<JsonElement, Long> loadRaw(BasicDBObject raw)
|
||||||
{
|
{
|
||||||
if (raw == null) return null;
|
if (raw == null) return new SimpleEntry<JsonElement, Long>(null, 0L);
|
||||||
|
|
||||||
// Throw away the id field
|
// Throw away the id field
|
||||||
raw.removeField(ID_FIELD);
|
raw.removeField(ID_FIELD);
|
||||||
|
|
||||||
// In case there is no _mtime set we assume 0. Probably a manual database addition by the server owner.
|
// In case there is no _mtime set we assume 1337.
|
||||||
Long mtime = 0L;
|
// NOTE: We can not use 0 since that one is reserved for errors.
|
||||||
|
// Probably a manual database addition by the server owner.
|
||||||
|
long mtime = 1337L;
|
||||||
Object mtimeObject = raw.removeField(MTIME_FIELD);
|
Object mtimeObject = raw.removeField(MTIME_FIELD);
|
||||||
if (mtimeObject != null)
|
if (mtimeObject != null)
|
||||||
{
|
{
|
||||||
@ -207,9 +230,9 @@ public class DriverMongo extends DriverAbstract
|
|||||||
|
|
||||||
// Get Entry
|
// Get Entry
|
||||||
Entry<JsonElement, Long> entry = loadRaw(raw);
|
Entry<JsonElement, Long> entry = loadRaw(raw);
|
||||||
//if (entry == null) continue;
|
// NOTE: The entry can be a failed one with null and 0.
|
||||||
// Actually allow adding null entries!
|
// NOTE: We add it anyways since it's an informative failure.
|
||||||
// they are informative failures!
|
// NOTE: This is supported by our defined specification.
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
ret.put(id, entry);
|
ret.put(id, entry);
|
||||||
@ -226,13 +249,13 @@ public class DriverMongo extends DriverAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long save(Coll<?> coll, String id, JsonElement data)
|
public long save(Coll<?> coll, String id, JsonElement data)
|
||||||
{
|
{
|
||||||
DBCollection dbcoll = fixColl(coll);
|
DBCollection dbcoll = fixColl(coll);
|
||||||
|
|
||||||
BasicDBObject dbo = new BasicDBObject();
|
BasicDBObject dbo = new BasicDBObject();
|
||||||
|
|
||||||
Long mtime = System.currentTimeMillis();
|
long mtime = System.currentTimeMillis();
|
||||||
dbo.put(ID_FIELD, id);
|
dbo.put(ID_FIELD, id);
|
||||||
dbo.put(MTIME_FIELD, mtime);
|
dbo.put(MTIME_FIELD, mtime);
|
||||||
|
|
||||||
|
@ -109,15 +109,15 @@ public abstract class Entity<E extends Entity<E>> implements Comparable<E>
|
|||||||
Coll<E> coll = this.getColl();
|
Coll<E> coll = this.getColl();
|
||||||
if (coll == null) return;
|
if (coll == null) return;
|
||||||
|
|
||||||
if (!coll.inited()) return;
|
if ( ! coll.inited()) return;
|
||||||
|
|
||||||
coll.changedIds.add(id);
|
coll.identifiedModifications.put(id, Modification.UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModificationState sync()
|
public Modification sync()
|
||||||
{
|
{
|
||||||
String id = this.getId();
|
String id = this.getId();
|
||||||
if (id == null) return ModificationState.UNKNOWN;
|
if (id == null) return Modification.UNKNOWN;
|
||||||
return this.getColl().syncId(id);
|
return this.getColl().syncId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ public abstract class Entity<E extends Entity<E>> implements Comparable<E>
|
|||||||
String id = this.getId();
|
String id = this.getId();
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
|
|
||||||
this.getColl().loadFromRemote(id, null, false);
|
this.getColl().loadFromRemote(id, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
@ -43,7 +43,7 @@ public class ExamineThread extends Thread
|
|||||||
long before = System.currentTimeMillis();
|
long before = System.currentTimeMillis();
|
||||||
for (Coll<?> coll : Coll.getInstances())
|
for (Coll<?> coll : Coll.getInstances())
|
||||||
{
|
{
|
||||||
coll.findSuspects();
|
coll.identifyModifications();
|
||||||
}
|
}
|
||||||
long after = System.currentTimeMillis();
|
long after = System.currentTimeMillis();
|
||||||
long duration = after-before;
|
long duration = after-before;
|
||||||
|
@ -15,7 +15,7 @@ public class JsonFileFilter implements FileFilter
|
|||||||
// INSTANCE & CONSTRUCT
|
// INSTANCE & CONSTRUCT
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
|
||||||
private static JsonFileFilter i = new JsonFileFilter();
|
private static final JsonFileFilter i = new JsonFileFilter();
|
||||||
public static JsonFileFilter get() { return i; }
|
public static JsonFileFilter get() { return i; }
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
@ -18,8 +18,8 @@ public class MStore
|
|||||||
private static Map<String, Driver> drivers = new HashMap<String, Driver>();
|
private static Map<String, Driver> drivers = new HashMap<String, Driver>();
|
||||||
public static boolean registerDriver(Driver driver)
|
public static boolean registerDriver(Driver driver)
|
||||||
{
|
{
|
||||||
if (drivers.containsKey(driver.getName())) return false;
|
if (drivers.containsKey(driver.getDriverName())) return false;
|
||||||
drivers.put(driver.getName(), driver);
|
drivers.put(driver.getDriverName(), driver);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.massivecraft.massivecore.store;
|
package com.massivecraft.massivecore.store;
|
||||||
|
|
||||||
public enum ModificationState
|
public enum Modification
|
||||||
{
|
{
|
||||||
LOCAL_ALTER (true, true),
|
LOCAL_ALTER (true, true),
|
||||||
LOCAL_ATTACH (true, true),
|
LOCAL_ATTACH (true, true),
|
||||||
@ -19,7 +19,7 @@ public enum ModificationState
|
|||||||
public boolean isLocal() { return this.local; }
|
public boolean isLocal() { return this.local; }
|
||||||
public boolean isRemote() { return this.local == false; }
|
public boolean isRemote() { return this.local == false; }
|
||||||
|
|
||||||
private ModificationState(boolean modified, boolean local)
|
private Modification(boolean modified, boolean local)
|
||||||
{
|
{
|
||||||
this.modified = modified;
|
this.modified = modified;
|
||||||
this.local = local;
|
this.local = local;
|
Loading…
Reference in New Issue
Block a user