Optimize TickTask (reduce footprint of copying), code formatting.

This commit is contained in:
asofold 2014-11-02 23:35:27 +01:00
parent 0118f4334f
commit 27913a758d

View File

@ -1,6 +1,5 @@
package fr.neatmonster.nocheatplus.utilities;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@ -32,14 +31,16 @@ public class TickTask implements Runnable {
public CheckType checkType;
public String playerName;
private final int hashCode;
public PermissionUpdateEntry(final String playerName, final CheckType checkType){
public PermissionUpdateEntry(final String playerName, final CheckType checkType) {
this.playerName = playerName;
this.checkType = checkType;
hashCode = playerName.hashCode() ^ checkType.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof PermissionUpdateEntry)) return false;
if (!(obj instanceof PermissionUpdateEntry)) {
return false;
}
final PermissionUpdateEntry other = (PermissionUpdateEntry) obj;
return playerName.equals(other.playerName) && checkType.equals(other.checkType);
}
@ -51,11 +52,15 @@ public class TickTask implements Runnable {
public static final int lagMaxTicks = 80;
/** Lock for accessing permissionUpdates. */
private static final Object permissionLock = new Object();
/** Permissions to update: player name -> check type. */
private static final Set<PermissionUpdateEntry> permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
private static Set<PermissionUpdateEntry> permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
/** Lock for delayedActions. */
private static final Object actionLock = new Object();
/** Actions to execute. */
private static final List<ViolationData> delayedActions = new LinkedList<ViolationData>();
private static List<ViolationData> delayedActions = new LinkedList<ViolationData>();
/** Tick listeners to call every tick. */
private static final Set<TickListener> tickListeners = new LinkedHashSet<TickListener>();
@ -88,7 +93,7 @@ public class TickTask implements Runnable {
protected static boolean locked = true;
static{
for (int i = 0; i < spikeDurations.length; i++){
for (int i = 0; i < spikeDurations.length; i++) {
spikes[i] = new ActionFrequency(3, 1000L * 60L * 20L);
}
}
@ -100,13 +105,15 @@ public class TickTask implements Runnable {
*/
public static void executeActions() {
final List<ViolationData> copyActions;
synchronized (delayedActions) {
if (delayedActions.isEmpty()) return;
copyActions = new ArrayList<ViolationData>(delayedActions);
delayedActions.clear();
synchronized (actionLock) {
if (delayedActions.isEmpty()) {
return;
}
copyActions = delayedActions;
delayedActions = new LinkedList<ViolationData>();
}
for (int i = 0; i < copyActions.size(); i++){
copyActions.get(i).executeActions();
for (final ViolationData vd : copyActions) {
vd.executeActions();
}
}
@ -115,25 +122,31 @@ public class TickTask implements Runnable {
* Note: Only call from the main thread!
*/
public static void updatePermissions() {
final List<PermissionUpdateEntry> copyPermissions;
synchronized (permissionUpdates) {
if (permissionUpdates.isEmpty()) return;
copyPermissions = new ArrayList<PermissionUpdateEntry>(permissionUpdates);
permissionUpdates.clear();
final Set<PermissionUpdateEntry> copyPermissions;
synchronized (permissionLock) {
if (permissionUpdates.isEmpty()) {
return;
}
copyPermissions = permissionUpdates;
permissionUpdates = new LinkedHashSet<PermissionUpdateEntry>(50);
}
for (int i = 0; i < copyPermissions.size(); i++){
final PermissionUpdateEntry entry = copyPermissions.get(i);
for (final PermissionUpdateEntry entry : copyPermissions) {
final Player player = DataManager.getPlayer(entry.playerName); // Might use exact name by contract.
if (player == null || !player.isOnline()) continue;
if (player == null || !player.isOnline()) {
continue;
}
final String[] perms = entry.checkType.getConfigFactory().getConfig(player).getCachePermissions();
if (perms == null) continue;
if (perms == null) {
continue;
}
final ICheckData data = entry.checkType.getDataFactory().getData(player);
for (int j = 0; j < perms.length; j ++){
for (int j = 0; j < perms.length; j ++) {
final String permission = perms[j];
data.setCachedPermission(permission, player.hasPermission(permission));
}
}
}
// Public static access methods
/**
* Access method to request permission updates.<br>
@ -141,9 +154,11 @@ public class TickTask implements Runnable {
* @param playerName
* @param checkType
*/
public static void requestPermissionUpdate(final String playerName, final CheckType checkType){
synchronized(permissionUpdates){
if (locked) return;
public static void requestPermissionUpdate(final String playerName, final CheckType checkType) {
synchronized(permissionLock) {
if (locked) {
return;
}
permissionUpdates.add(new PermissionUpdateEntry(playerName, checkType));
}
}
@ -154,8 +169,10 @@ public class TickTask implements Runnable {
* @param actions
*/
public static void requestActionsExecution(final ViolationData actions) {
synchronized (delayedActions) {
if (locked) return;
synchronized (actionLock) {
if (locked) {
return;
}
delayedActions.add(actions);
}
}
@ -168,13 +185,15 @@ public class TickTask implements Runnable {
* <li>For OnDemandTickListenerS, setRegistered(true) will get called if not locked.</li>
* @param listener
*/
public static void addTickListener(TickListener listener){
public static void addTickListener(TickListener listener) {
synchronized (tickListeners) {
if (locked) return; // TODO: Boolean return value ?
if (!tickListeners.contains(listener)){
if (locked) {
return; // TODO: Boolean return value ?
}
if (!tickListeners.contains(listener)) {
tickListeners.add(listener);
}
if (listener instanceof OnDemandTickListener){
if (listener instanceof OnDemandTickListener) {
((OnDemandTickListener) listener).setRegistered(true);
}
}
@ -189,9 +208,9 @@ public class TickTask implements Runnable {
* @param listener
* @return If previously contained.
*/
public static boolean removeTickListener(TickListener listener){
public static boolean removeTickListener(TickListener listener) {
synchronized (tickListeners) {
if (listener instanceof OnDemandTickListener){
if (listener instanceof OnDemandTickListener) {
((OnDemandTickListener) listener).setRegistered(false);
}
return tickListeners.remove(listener);
@ -208,15 +227,15 @@ public class TickTask implements Runnable {
public static void removeAllTickListeners() {
synchronized (tickListeners) {
// Gracefully set OnDemandTickListeners to unregistered.
for (final TickListener listener : tickListeners){
if (listener instanceof OnDemandTickListener){
for (final TickListener listener : tickListeners) {
if (listener instanceof OnDemandTickListener) {
try{
final OnDemandTickListener odtl = (OnDemandTickListener) listener;
if (odtl.isRegistered()){ // Could use the flag, but this is better.
if (odtl.isRegistered()) { // Could use the flag, but this is better.
odtl.setRegistered(false);
}
}
catch(Throwable t){
catch(Throwable t) {
// Unlikely.
LogUtil.logWarning("[NoCheatPlus] Failed to set OnDemandTickListener to unregistered state: " + t.getClass().getSimpleName());
LogUtil.logWarning(t);
@ -233,7 +252,7 @@ public class TickTask implements Runnable {
* NOTE: Can be called from other threads.
* @return The current tick count.
*/
public static final int getTick(){
public static final int getTick() {
return tick;
}
@ -241,7 +260,7 @@ public class TickTask implements Runnable {
* Get the time at which the task was started.
* @return
*/
public static final long getTimeStart(){
public static final long getTimeStart() {
return timeStart;
}
@ -249,7 +268,7 @@ public class TickTask implements Runnable {
* Time when last time processing was finished.
* @return
*/
public static final long getTimeLast(){
public static final long getTimeLast() {
return timeLast;
}
@ -259,7 +278,7 @@ public class TickTask implements Runnable {
* @param ms Past milliseconds to cover. A longer period of time may be used, up to two times if ms > lagMaxTicks * 50.
* @return Lag factor (1.0 = 20 tps, 2.0 = 10 tps), excluding the current tick.
*/
public static final float getLag(final long ms){
public static final float getLag(final long ms) {
return getLag(ms, false);
}
@ -270,16 +289,18 @@ public class TickTask implements Runnable {
* @param exact If to include the currently running tick, if possible. Should only be set to true, if called from the main thread (or while the main thread is blocked).
* @return Lag factor (1.0 = 20 tps, 2.0 = 10 tps).
*/
public static final float getLag(final long ms, final boolean exact){
if (ms < 0){
public static final float getLag(final long ms, final boolean exact) {
if (ms < 0) {
// Account for freezing (i.e. check timeLast, might be an extra method)!
return getLag(0, exact);
}
else if (ms > lagMaxCoveredMs){
else if (ms > lagMaxCoveredMs) {
return getLag(lagMaxCoveredMs, exact);
}
final int tick = TickTask.tick;
if (tick == 0) return 1f;
if (tick == 0) {
return 1f;
}
final int add = ms > 0 && (ms % 50) == 0 ? 0 : 1;
// TODO: Consider: Put "exact" block here, subtract a tick if appropriate?
final int totalTicks = Math.min(tick, add + (int) (ms / 50));
@ -288,17 +309,19 @@ public class TickTask implements Runnable {
long covered = maxTick * 50;
// Only count fully covered:
if (totalTicks > lagMaxTicks){
if (totalTicks > lagMaxTicks) {
int maxTickSq = Math.min(lagMaxTicks, totalTicks / lagMaxTicks);
if (lagMaxTicks * maxTickSq == totalTicks) maxTickSq -= 1;
if (lagMaxTicks * maxTickSq == totalTicks) {
maxTickSq -= 1;
}
sum += tickDurationsSq[maxTickSq - 1];
covered += lagMaxTicks * 50 * maxTickSq;
}
if (exact){
if (exact) {
// Attempt to count in the current tick.
final long passed = System.currentTimeMillis() - timeLast;
if (passed > 50){
if (passed > 50) {
// Only count in in the case of "overtime".
covered += 50;
sum += passed;
@ -313,7 +336,7 @@ public class TickTask implements Runnable {
* @deprecated What is moderate :) ?
* @return
*/
public static final int getModerateLagSpikes(){
public static final int getModerateLagSpikes() {
spikes[0].update(System.currentTimeMillis());
return (int) spikes[0].score(1f);
}
@ -323,7 +346,7 @@ public class TickTask implements Runnable {
* @deprecated What is heavy :) ?
* @return
*/
public static final int getHeavyLagSpikes(){
public static final int getHeavyLagSpikes() {
spikes[1].update(System.currentTimeMillis());
return (int) spikes[1].score(1f);
}
@ -332,7 +355,7 @@ public class TickTask implements Runnable {
* Get total number of lag spikes counted at all. This is the number of lag spikes with a duration above spikeDuations[0] which should be 150 ms. This is the score of spikes[0].
* @return
*/
public static final int getNumberOfLagSpikes(){
public static final int getNumberOfLagSpikes() {
spikes[0].update(System.currentTimeMillis());
return (int) spikes[0].score(1f);
}
@ -341,7 +364,7 @@ public class TickTask implements Runnable {
* Get the stepping for lag spike duration tracking.
* @return
*/
public static final long[] getLagSpikeDurations(){
public static final long[] getLagSpikeDurations() {
return Arrays.copyOf(spikeDurations, spikeDurations.length);
}
@ -349,10 +372,10 @@ public class TickTask implements Runnable {
* Get lag spike count according to getLagSpikeDurations() values. Entries of lower indexes contain the entries of higher indexes (so subtraction would be necessary to get spikes from...to).
* @return
*/
public static final int[] getLagSpikes(){
public static final int[] getLagSpikes() {
final int[] out = new int[spikeDurations.length];
final long now = System.currentTimeMillis();
for (int i = 0; i < spikeDurations.length; i++){
for (int i = 0; i < spikeDurations.length; i++) {
spikes[i].update(now);
out[i] = (int) spikes[i].score(1f);
}
@ -363,21 +386,27 @@ public class TickTask implements Runnable {
* Check if new permission update requests and actions can be added.
* @return True if locked.
*/
public boolean isLocked(){
public boolean isLocked() {
return locked;
}
// Public methods for internal use.
public static int start(final Plugin plugin){
public static int start(final Plugin plugin) {
cancel();
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, new TickTask(), 1, 1);
if (taskId != -1) timeStart = System.currentTimeMillis();
else timeStart = 0;
if (taskId != -1) {
timeStart = System.currentTimeMillis();
}
else {
timeStart = 0;
}
return taskId;
}
public static void cancel(){
if (taskId == -1) return;
public static void cancel() {
if (taskId == -1) {
return;
}
Bukkit.getScheduler().cancelTask(taskId);
taskId = -1;
}
@ -387,18 +416,18 @@ public class TickTask implements Runnable {
* NOTE: This is just a flag, no sync is done here.
* @param locked
*/
public static void setLocked(boolean locked){
public static void setLocked(boolean locked) {
TickTask.locked = locked;
}
/**
* Empty queues (better call after setLocked(true)) and tickListeners.
*/
public static void purge(){
synchronized (permissionUpdates) {
public static void purge() {
synchronized (permissionLock) {
permissionUpdates.clear();
}
synchronized (delayedActions) {
synchronized (actionLock) {
delayedActions.clear();
}
synchronized (tickListeners) {
@ -409,14 +438,14 @@ public class TickTask implements Runnable {
/**
* Reset tick and tick stats to 0 (!).
*/
public static void reset(){
public static void reset() {
tick = 0;
timeLast = 0;
for (int i = 0; i < lagMaxTicks; i++){
for (int i = 0; i < lagMaxTicks; i++) {
tickDurations[i] = 0;
tickDurationsSq[i] = 0;
}
for (int i = 0; i < spikeDurations.length; i++){
for (int i = 0; i < spikeDurations.length; i++) {
spikes[i].clear(0);
}
}
@ -428,23 +457,24 @@ public class TickTask implements Runnable {
*
*/
private final void notifyListeners() {
final List<TickListener> copyListeners;
// Copy for iterating, to allow reentrant registration while processing.
final TickListener[] copyListeners;
synchronized (tickListeners) {
// Synchronized to allow concurrent adding and removal.
// (Ignores the locked state while still running.)
// TODO: Policy for locked state. Though locking should only happen during onDisable, so before / after the task is run anyway.
if (tickListeners.isEmpty()){
if (tickListeners.isEmpty()) {
// Future purpose.
return;
}
copyListeners = new ArrayList<TickListener>(tickListeners);
}
for (int i = 0; i < copyListeners.size(); i++){
final TickListener listener = copyListeners.get(i);
copyListeners = tickListeners.toArray(new TickListener[tickListeners.size()]);
}
for (int i = 0; i < copyListeners.length; i++) {
final TickListener listener = copyListeners[i];
try{
listener.onTick(tick, timeLast);
}
catch(Throwable t){
catch(Throwable t) {
LogUtil.logSevere("[NoCheatPlus] (TickTask) TickListener generated an exception:");
LogUtil.logSevere(t);
}
@ -469,37 +499,37 @@ public class TickTask implements Runnable {
LogUtil.logWarning("[NoCheatPlus] System time ran backwards (" + timeLast + "->" + time + "), clear all data and history...");
DataManager.clearData(CheckType.ALL);
lastDur = 50;
for (int i = 0; i < spikeDurations.length; i++){
for (int i = 0; i < spikeDurations.length; i++) {
spikes[i].clear(0);
}
}
else if (tick > 0){
else if (tick > 0) {
lastDur = time - timeLast;
}
else{
else {
lastDur = 50;
}
// Update sums of sums of tick durations.
if (tick > 0 && (tick % lagMaxTicks) == 0){
if (tick > 0 && (tick % lagMaxTicks) == 0) {
final long sum = tickDurations[lagMaxTicks - 1];
for (int i = 1; i < lagMaxTicks; i++){
for (int i = 1; i < lagMaxTicks; i++) {
tickDurationsSq[i] = tickDurationsSq[i - 1] + sum;
}
tickDurationsSq[0] = sum;
}
// Update tick duration sums.
for (int i = 1; i < lagMaxTicks; i++){
for (int i = 1; i < lagMaxTicks; i++) {
tickDurations[i] = tickDurations[i - 1] + lastDur;
}
tickDurations[0] = lastDur;
// Lag spikes counting. [Subject to adjustments!]
if (lastDur > spikeDurations[0] && tick > 0){
if (lastDur > spikeDurations[0] && tick > 0) {
spikes[0].add(time, 1f);
for (int i = 1; i < spikeDurations.length; i++){
if (lastDur > spikeDurations[i]){
for (int i = 1; i < spikeDurations.length; i++) {
if (lastDur > spikeDurations[i]) {
spikes[i].add(time, 1f);
}
else break;