Implemented a recursive equality checker for JsonElement. Compensates for MongoDB rounding issues, non deterministic map entry order etc. Also reduces CPU load with 30-40%.
This commit is contained in:
parent
b50c8cd048
commit
6d57d6f51c
@ -139,7 +139,7 @@ public class DriverMongo extends DriverAbstract
|
|||||||
Long mtime = ((Number)raw.removeField(MTIME_FIELD)).longValue();
|
Long mtime = ((Number)raw.removeField(MTIME_FIELD)).longValue();
|
||||||
raw.removeField(ID_FIELD);
|
raw.removeField(ID_FIELD);
|
||||||
|
|
||||||
JsonElement element = MongoGsonConverter.mongo2GsonObject(raw);
|
JsonElement element = GsonMongoConverter.mongo2GsonObject(raw);
|
||||||
|
|
||||||
return new SimpleEntry<JsonElement, Long>(element, mtime);
|
return new SimpleEntry<JsonElement, Long>(element, mtime);
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ public class DriverMongo extends DriverAbstract
|
|||||||
{
|
{
|
||||||
DBCollection dbcoll = fixColl(coll);
|
DBCollection dbcoll = fixColl(coll);
|
||||||
|
|
||||||
BasicDBObject dbo = MongoGsonConverter.gson2MongoObject(data);
|
BasicDBObject dbo = GsonMongoConverter.gson2MongoObject(data);
|
||||||
Long mtime = System.currentTimeMillis();
|
Long mtime = System.currentTimeMillis();
|
||||||
dbo.put(MTIME_FIELD, mtime);
|
dbo.put(MTIME_FIELD, mtime);
|
||||||
dbo.put(ID_FIELD, id);
|
dbo.put(ID_FIELD, id);
|
||||||
|
177
src/com/massivecraft/mcore/store/GsonEqualsChecker.java
Normal file
177
src/com/massivecraft/mcore/store/GsonEqualsChecker.java
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package com.massivecraft.mcore.store;
|
||||||
|
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
import com.massivecraft.mcore.xlib.gson.JsonArray;
|
||||||
|
import com.massivecraft.mcore.xlib.gson.JsonElement;
|
||||||
|
import com.massivecraft.mcore.xlib.gson.JsonNull;
|
||||||
|
import com.massivecraft.mcore.xlib.gson.JsonObject;
|
||||||
|
import com.massivecraft.mcore.xlib.gson.JsonPrimitive;
|
||||||
|
import com.massivecraft.mcore.xlib.gson.internal.LazilyParsedNumber;
|
||||||
|
|
||||||
|
public class GsonEqualsChecker
|
||||||
|
{
|
||||||
|
// The argument one must be JsonElement, and can not be null.
|
||||||
|
// The argument twoObject may be anything, even null.
|
||||||
|
public static boolean equals(JsonElement one, Object twoObject)
|
||||||
|
{
|
||||||
|
// Null check (one can't ever be null)
|
||||||
|
if (twoObject == null) return false;
|
||||||
|
|
||||||
|
// Object identity speedup
|
||||||
|
if (one == twoObject) return true;
|
||||||
|
|
||||||
|
// Type-Switch
|
||||||
|
if (one.isJsonObject())
|
||||||
|
{
|
||||||
|
// JsonObject
|
||||||
|
return objectEquals((JsonObject)one, twoObject);
|
||||||
|
}
|
||||||
|
else if (one.isJsonArray())
|
||||||
|
{
|
||||||
|
// JsonArray
|
||||||
|
return arrayEquals((JsonArray)one, twoObject);
|
||||||
|
}
|
||||||
|
else if (one.isJsonPrimitive())
|
||||||
|
{
|
||||||
|
// JsonPrimitive
|
||||||
|
return primitiveEquals((JsonPrimitive)one, twoObject);
|
||||||
|
}
|
||||||
|
else if (one.isJsonNull())
|
||||||
|
{
|
||||||
|
// JsonNull
|
||||||
|
return nullEquals((JsonNull)one, twoObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ???
|
||||||
|
throw new IllegalArgumentException("Unsupported value type for: " + one);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The argument one must be JsonObject, and can not be null.
|
||||||
|
// The argument twoObject may be anything, even null.
|
||||||
|
public static boolean objectEquals(JsonObject one, Object twoObject)
|
||||||
|
{
|
||||||
|
// Null check (one can't ever be null)
|
||||||
|
if (twoObject == null) return false;
|
||||||
|
|
||||||
|
// Object identity speedup
|
||||||
|
if (one == twoObject) return true;
|
||||||
|
|
||||||
|
// twoObject must be JsonObject
|
||||||
|
if (!(twoObject instanceof JsonObject)) return false;
|
||||||
|
|
||||||
|
// Cast to JsonObject
|
||||||
|
JsonObject two = (JsonObject)twoObject;
|
||||||
|
|
||||||
|
// Size must be the same
|
||||||
|
if (one.entrySet().size() != two.entrySet().size()) return false;
|
||||||
|
|
||||||
|
// And each entry must exist and be the same
|
||||||
|
for (Entry<String, JsonElement> entry : one.entrySet())
|
||||||
|
{
|
||||||
|
if (!equals(entry.getValue(), two.get(entry.getKey()))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The argument one must be JsonArray, and can not be null.
|
||||||
|
// The argument twoObject may be anything, even null.
|
||||||
|
public static boolean arrayEquals(JsonArray one, Object twoObject)
|
||||||
|
{
|
||||||
|
// Null check (one can't ever be null)
|
||||||
|
if (twoObject == null) return false;
|
||||||
|
|
||||||
|
// Object identity speedup
|
||||||
|
if (one == twoObject) return true;
|
||||||
|
|
||||||
|
// twoObject must be JsonArray
|
||||||
|
if (!(twoObject instanceof JsonArray)) return false;
|
||||||
|
|
||||||
|
// Cast to JsonArray
|
||||||
|
JsonArray two = (JsonArray)twoObject;
|
||||||
|
|
||||||
|
// Size must be the same
|
||||||
|
int size = one.size();
|
||||||
|
if (two.size() != size) return false;
|
||||||
|
|
||||||
|
// And each element index must be the same
|
||||||
|
for (int i = 0; i < size ; i++)
|
||||||
|
{
|
||||||
|
if (!equals(one.get(i), two.get(i))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The argument one must be JsonPrimitive, and can not be null.
|
||||||
|
// The argument twoObject may be anything, even null.
|
||||||
|
public static boolean primitiveEquals(JsonPrimitive one, Object twoObject)
|
||||||
|
{
|
||||||
|
// Null check (one can't ever be null)
|
||||||
|
if (twoObject == null) return false;
|
||||||
|
|
||||||
|
// Object identity speedup
|
||||||
|
if (one == twoObject) return true;
|
||||||
|
|
||||||
|
// if twoObject is JsonObject or JsonArray we are not equal.
|
||||||
|
if (!(twoObject instanceof JsonPrimitive)) return false;
|
||||||
|
|
||||||
|
// Cast to JsonPrimitive
|
||||||
|
JsonPrimitive two = (JsonPrimitive)twoObject;
|
||||||
|
|
||||||
|
// Boolean check
|
||||||
|
if (one.isBoolean())
|
||||||
|
{
|
||||||
|
return one.getAsBoolean() == two.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number check
|
||||||
|
if (one.isNumber())
|
||||||
|
{
|
||||||
|
Number oneNumber = one.getAsNumber();
|
||||||
|
Number twoNumber = two.getAsNumber();
|
||||||
|
|
||||||
|
boolean floating;
|
||||||
|
if (oneNumber instanceof LazilyParsedNumber)
|
||||||
|
{
|
||||||
|
floating = StringUtils.contains(oneNumber.toString(), '.');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
floating = (oneNumber instanceof Double || oneNumber instanceof Float);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floating)
|
||||||
|
{
|
||||||
|
// Our epsilon is pretty big in order to see float and double as the same.
|
||||||
|
return Math.abs(oneNumber.doubleValue() - twoNumber.doubleValue()) < 0.0001D;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return oneNumber.longValue() == twoNumber.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// String check
|
||||||
|
if (one.isString())
|
||||||
|
{
|
||||||
|
return one.getAsString().equals(two.getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unsupported value type for: " + one);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The argument one must be JsonNull, and can not be null.
|
||||||
|
// The argument twoObject may be anything, even null.
|
||||||
|
public static boolean nullEquals(JsonNull one, Object twoObject)
|
||||||
|
{
|
||||||
|
// Null check (one can't ever be null)
|
||||||
|
if (twoObject == null) return false;
|
||||||
|
|
||||||
|
return twoObject == JsonNull.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import com.massivecraft.mcore.xlib.mongodb.BasicDBList;
|
|||||||
import com.massivecraft.mcore.xlib.mongodb.BasicDBObject;
|
import com.massivecraft.mcore.xlib.mongodb.BasicDBObject;
|
||||||
import com.massivecraft.mcore.xlib.mongodb.DBObject;
|
import com.massivecraft.mcore.xlib.mongodb.DBObject;
|
||||||
|
|
||||||
public final class MongoGsonConverter
|
public final class GsonMongoConverter
|
||||||
{
|
{
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
// CONSTANTS
|
// CONSTANTS
|
@ -52,7 +52,7 @@ public class MStore
|
|||||||
if (one == null) return two == null;
|
if (one == null) return two == null;
|
||||||
if (two == null) return one == null;
|
if (two == null) return one == null;
|
||||||
|
|
||||||
return one.toString().equals(two.toString());
|
return GsonEqualsChecker.equals(one, two);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------- //
|
// -------------------------------------------- //
|
||||||
|
Loading…
Reference in New Issue
Block a user