-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved recount code. Should be accurate.
This uses the latest approach done by Level addon. This does not yet include entity recounting! #123
- Loading branch information
1 parent
4cff598
commit 343d7bb
Showing
9 changed files
with
608 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
src/main/java/world/bentobox/limits/calculators/Pipeliner.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package world.bentobox.limits.calculators; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Queue; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ConcurrentLinkedQueue; | ||
|
||
import org.bukkit.Bukkit; | ||
import org.bukkit.scheduler.BukkitTask; | ||
|
||
import world.bentobox.bentobox.BentoBox; | ||
import world.bentobox.bentobox.database.objects.Island; | ||
import world.bentobox.limits.Limits; | ||
import world.bentobox.limits.calculators.Results.Result; | ||
|
||
/** | ||
* A pipeliner that will process one island at a time | ||
* @author tastybento | ||
* | ||
*/ | ||
public class Pipeliner { | ||
|
||
private static final int START_DURATION = 10; // 10 seconds | ||
private static final int CONCURRENT_COUNTS = 1; | ||
private final Queue<RecountCalculator> toProcessQueue; | ||
private final Map<RecountCalculator, Long> inProcessQueue; | ||
private final BukkitTask task; | ||
private final Limits addon; | ||
private long time; | ||
private long count; | ||
|
||
/** | ||
* Construct the pipeliner | ||
*/ | ||
public Pipeliner(Limits addon) { | ||
this.addon = addon; | ||
toProcessQueue = new ConcurrentLinkedQueue<>(); | ||
inProcessQueue = new HashMap<>(); | ||
// Loop continuously - check every tick if there is an island to scan | ||
task = Bukkit.getScheduler().runTaskTimer(BentoBox.getInstance(), () -> { | ||
if (!BentoBox.getInstance().isEnabled()) { | ||
cancel(); | ||
return; | ||
} | ||
// Complete the current to Process queue first | ||
if (!inProcessQueue.isEmpty() || toProcessQueue.isEmpty()) return; | ||
for (int j = 0; j < CONCURRENT_COUNTS && !toProcessQueue.isEmpty(); j++) { | ||
RecountCalculator iD = toProcessQueue.poll(); | ||
// Ignore deleted or unonwed islands | ||
if (!iD.getIsland().isDeleted() && !iD.getIsland().isUnowned()) { | ||
inProcessQueue.put(iD, System.currentTimeMillis()); | ||
// Start the scanning of a island with the first chunk | ||
scanIsland(iD); | ||
} | ||
} | ||
}, 1L, 10L); | ||
} | ||
|
||
private void cancel() { | ||
task.cancel(); | ||
} | ||
|
||
/** | ||
* @return number of islands currently in the queue or in process | ||
*/ | ||
public int getIslandsInQueue() { | ||
return inProcessQueue.size() + toProcessQueue.size(); | ||
} | ||
|
||
/** | ||
* Scans one chunk of an island and adds the results to a results object | ||
* @param iD | ||
*/ | ||
private void scanIsland(RecountCalculator iD) { | ||
if (iD.getIsland().isDeleted() || iD.getIsland().isUnowned() || task.isCancelled()) { | ||
// Island is deleted, so finish early with nothing | ||
inProcessQueue.remove(iD); | ||
iD.getR().complete(null); | ||
return; | ||
} | ||
iD.scanIsland(this); | ||
} | ||
|
||
|
||
/** | ||
* Adds an island to the scanning queue but only if the island is not already in the queue | ||
* @param island - the island to scan | ||
* @return CompletableFuture of the results. Results will be null if the island is already in the queue | ||
*/ | ||
public CompletableFuture<Results> addIsland(Island island) { | ||
// Check if queue already contains island | ||
if (inProcessQueue.keySet().parallelStream().map(RecountCalculator::getIsland).anyMatch(island::equals) | ||
|| toProcessQueue.parallelStream().map(RecountCalculator::getIsland).anyMatch(island::equals)) { | ||
return CompletableFuture.completedFuture(new Results(Result.IN_PROGRESS)); | ||
} | ||
return addToQueue(island); | ||
} | ||
|
||
private CompletableFuture<Results> addToQueue(Island island) { | ||
CompletableFuture<Results> r = new CompletableFuture<>(); | ||
toProcessQueue.add(new RecountCalculator(addon, island, r)); | ||
count++; | ||
return r; | ||
} | ||
|
||
/** | ||
* Get the average time it takes to run a level check | ||
* @return the average time in seconds | ||
*/ | ||
public int getTime() { | ||
return time == 0 || count == 0 ? START_DURATION : (int)((double)time/count/1000); | ||
} | ||
|
||
/** | ||
* Submit how long a level check took | ||
* @param time the time to set | ||
*/ | ||
public void setTime(long time) { | ||
// Running average | ||
this.time += time; | ||
} | ||
|
||
/** | ||
* Stop the current queue. | ||
*/ | ||
public void stop() { | ||
addon.log("Stopping Level queue"); | ||
task.cancel(); | ||
this.inProcessQueue.clear(); | ||
this.toProcessQueue.clear(); | ||
} | ||
|
||
/** | ||
* @return the inProcessQueue | ||
*/ | ||
protected Map<RecountCalculator, Long> getInProcessQueue() { | ||
return inProcessQueue; | ||
} | ||
|
||
/** | ||
* @return the task | ||
*/ | ||
protected BukkitTask getTask() { | ||
return task; | ||
} | ||
|
||
|
||
|
||
|
||
} |
Oops, something went wrong.