UserData is now copied to avoid null pointer exception after some data
is removed from cache while analysis is running.
Additionally added access and stopAccessing to analysis in case the copy
constructor is somehow flawed, to prevent the data from getting cleared
while analysis is being run.
Also added clear prevention to inspect cache if the data is accessed.
This commit is contained in:
Rsl1122 2017-03-09 20:52:05 +02:00
parent ef57c59d43
commit 236a2bd702
5 changed files with 132 additions and 21 deletions

View File

@ -6,9 +6,11 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.Gender;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@ -127,6 +129,43 @@ public class UserData {
playerKills = new ArrayList<>(); playerKills = new ArrayList<>();
} }
/**
* Creates a new UserData object with copied values.
* @param data UserData to copy into the new object.
*/
public UserData(UserData data) {
this.accessing = 0;
this.uuid = data.getUuid();
this.location = data.getLocation();
this.locations = new ArrayList<>();
locations.addAll(data.getLocations());
this.ips = new HashSet<>();
ips.addAll(data.getIps());
this.nicknames = new HashSet<>();
nicknames.addAll(data.getNicknames());
this.lastNick = data.getLastNick();
this.registered = data.getRegistered();
this.lastPlayed = data.getLastPlayed();
this.playTime = data.getPlayTime();
this.loginTimes = data.getLoginTimes();
this.timesKicked = data.getTimesKicked();
this.lastGmSwapTime = data.getLastGmSwapTime();
this.lastGamemode = data.getLastGamemode();
this.gmTimes = new HashMap<>();
gmTimes.putAll(data.getGmTimes());
this.isOp = data.isOp();
this.isBanned = data.isBanned();
DemographicsData dem = data.getDemData();
this.demData = new DemographicsData(dem.getAge(), dem.getGender(), dem.getGeoLocation());
this.mobKills = data.getMobKills();
this.playerKills = data.getPlayerKills();
this.deaths = data.getDeaths();
this.name = data.getName();
this.isOnline = data.isOnline();
this.sessions = new ArrayList<>();
sessions.addAll(data.getSessions());
}
/** /**
* *
* @param ip * @param ip
@ -630,4 +669,75 @@ public class UserData {
public void setLastNick(String lastNick) { public void setLastNick(String lastNick) {
this.lastNick = lastNick; this.lastNick = lastNick;
} }
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserData other = (UserData) obj;
if (this.accessing != other.accessing) {
return false;
}
if (this.registered != other.registered) {
return false;
}
if (this.lastPlayed != other.lastPlayed) {
return false;
}
if (this.playTime != other.playTime) {
return false;
}
if (this.loginTimes != other.loginTimes) {
return false;
}
if (this.timesKicked != other.timesKicked) {
return false;
}
if (this.lastGmSwapTime != other.lastGmSwapTime) {
return false;
}
if (this.mobKills != other.mobKills) {
return false;
}
if (this.deaths != other.deaths) {
return false;
}
if (!Objects.equals(this.lastNick, other.lastNick)) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
if (!Objects.equals(this.uuid, other.uuid)) {
return false;
}
if (!Objects.equals(this.ips, other.ips)) {
return false;
}
if (!Objects.equals(this.nicknames, other.nicknames)) {
return false;
}
if (this.lastGamemode != other.lastGamemode) {
return false;
}
if (!Objects.equals(this.gmTimes, other.gmTimes)) {
return false;
}
if (!Objects.equals(this.playerKills, other.playerKills)) {
return false;
}
if (!Objects.equals(this.sessions, other.sessions)) {
return false;
}
return true;
}
} }

View File

@ -55,7 +55,7 @@ public class InspectCacheHandler {
DBCallableProcessor cacher = new DBCallableProcessor() { DBCallableProcessor cacher = new DBCallableProcessor() {
@Override @Override
public void process(UserData data) { public void process(UserData data) {
cache.put(uuid, data); cache.put(uuid, new UserData(data));
} }
}; };
handler.getUserDataForProcessing(cacher, uuid, false); handler.getUserDataForProcessing(cacher, uuid, false);
@ -69,7 +69,9 @@ public class InspectCacheHandler {
@Override @Override
public void run() { public void run() {
if (new Date().toInstant().getEpochSecond() - clearTimes.get(uuid) < 30) { if (new Date().toInstant().getEpochSecond() - clearTimes.get(uuid) < 30) {
if (!cache.get(uuid).isAccessed()) {
clearFomCache(uuid); clearFomCache(uuid);
}
} else { } else {
this.cancel(); this.cancel();
} }

View File

@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import main.java.com.djrapitops.plan.Phrase; import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.Settings;
@ -30,8 +31,6 @@ public class Analysis {
private final Plan plugin; private final Plan plugin;
private final InspectCacheHandler inspectCache; private final InspectCacheHandler inspectCache;
private final List<UserData> rawData;
private final List<UUID> added;
/** /**
* Class Constructor. * Class Constructor.
@ -41,8 +40,6 @@ public class Analysis {
public Analysis(Plan plugin) { public Analysis(Plan plugin) {
this.plugin = plugin; this.plugin = plugin;
this.inspectCache = plugin.getInspectCache(); this.inspectCache = plugin.getInspectCache();
rawData = new ArrayList<>();
added = new ArrayList<>();
} }
/** /**
@ -50,13 +47,13 @@ public class Analysis {
* *
* First retrieves all Offlineplayers and checks those that are in the * First retrieves all Offlineplayers and checks those that are in the
* database. Then Runs a new Analysis Task Asyncronously. Saves AnalysisData * database. Then Runs a new Analysis Task Asyncronously. Saves AnalysisData
* to the provided Cache. Saves all UserData to InspectCache for 8 minutes. * to the provided Cache. Saves all UserData to InspectCache for 15 minutes.
* *
* @param analysisCache Cache that the data is saved to. * @param analysisCache Cache that the data is saved to.
*/ */
public void analyze(AnalysisCacheHandler analysisCache) { public void analyze(AnalysisCacheHandler analysisCache) {
rawData.clear(); List<UserData> rawData = new ArrayList<>();
added.clear(); List<UUID> added = new ArrayList<>();
log(Phrase.ANALYSIS_START + ""); log(Phrase.ANALYSIS_START + "");
List<UUID> uuids = fetchPlayersInDB(); List<UUID> uuids = fetchPlayersInDB();
@ -68,7 +65,7 @@ public class Analysis {
BukkitTask asyncAnalysisTask = (new BukkitRunnable() { BukkitTask asyncAnalysisTask = (new BukkitRunnable() {
@Override @Override
public void run() { public void run() {
uuids.stream().filter(uuid -> uuid != null).forEach((uuid) -> { uuids.stream().forEach((uuid) -> {
inspectCache.cache(uuid, 15); inspectCache.cache(uuid, 15);
}); });
log(Phrase.ANALYSIS_FETCH_DATA + ""); log(Phrase.ANALYSIS_FETCH_DATA + "");
@ -80,6 +77,7 @@ public class Analysis {
UserData userData = inspectCache.getFromCache(uuid); UserData userData = inspectCache.getFromCache(uuid);
if (userData != null) { if (userData != null) {
rawData.add(userData); rawData.add(userData);
userData.access();
added.add(uuid); added.add(uuid);
} }
} }
@ -135,12 +133,12 @@ public class Analysis {
sorted.addTotalDeaths(uData.getDeaths()); sorted.addTotalDeaths(uData.getDeaths());
sorted.getSessiondata().addAll(uData.getSessions()); sorted.getSessiondata().addAll(uData.getSessions());
sorted.getRegistered().add(uData.getRegistered()); sorted.getRegistered().add(uData.getRegistered());
uData.stopAccessing();
} catch (NullPointerException e) { } catch (NullPointerException e) {
plugin.logError(Phrase.DATA_CORRUPTION_WARN.parse(uData.getUuid() + "")); plugin.logError(Phrase.DATA_CORRUPTION_WARN.parse(uData.getUuid() + ""));
plugin.toLog(this.getClass().getName(), e); plugin.toLog(this.getClass().getName(), e);
} }
}); });
// Analyze & Save RawAnalysisData to AnalysisData // Analyze & Save RawAnalysisData to AnalysisData
createPlayerActivityGraphs(analysisData, sorted.getSessiondata(), sorted.getRegistered()); createPlayerActivityGraphs(analysisData, sorted.getSessiondata(), sorted.getRegistered());
@ -240,19 +238,19 @@ public class Analysis {
} }
private List<UUID> fetchPlayersInDB() { private List<UUID> fetchPlayersInDB() {
final List<UUID> uuids = new ArrayList<>();
log(Phrase.ANALYSIS_FETCH_PLAYERS + "");
try { try {
// final List<UUID> uuids = new ArrayList<>();
log(Phrase.ANALYSIS_FETCH_PLAYERS + "");
Set<UUID> savedUUIDs = plugin.getDB().getSavedUUIDs(); Set<UUID> savedUUIDs = plugin.getDB().getSavedUUIDs();
savedUUIDs.parallelStream() List<UUID> uuids = savedUUIDs.parallelStream()
.filter(uuid -> uuid != null)
.filter((uuid) -> (getOfflinePlayer(uuid).hasPlayedBefore())) .filter((uuid) -> (getOfflinePlayer(uuid).hasPlayedBefore()))
.forEach((uuid) -> { .collect(Collectors.toList());
uuids.add(uuid); return uuids;
});
} catch (Exception e) { } catch (Exception e) {
plugin.toLog(this.getClass().getName(), e); plugin.toLog(this.getClass().getName(), e);
} }
return uuids; return new ArrayList<>();
} }
private void log(String msg) { private void log(String msg) {

View File

@ -75,6 +75,7 @@ public class AnalysisUtils {
int newPlayers = 0; int newPlayers = 0;
if (!registered.isEmpty()) { if (!registered.isEmpty()) {
newPlayers = registered.stream() newPlayers = registered.stream()
.filter((reg) -> (reg != null))
.filter((reg) -> (reg > now - scale)) .filter((reg) -> (reg > now - scale))
.map((_item) -> 1).reduce(newPlayers, Integer::sum); .map((_item) -> 1).reduce(newPlayers, Integer::sum);
} }

View File

@ -1,7 +1,7 @@
name: Plan name: Plan
author: Rsl1122 author: Rsl1122
main: main.java.com.djrapitops.plan.Plan main: main.java.com.djrapitops.plan.Plan
version: 2.8.0 version: 2.8.1
softdepend: softdepend:
- OnTime - OnTime