Fixes #30
The CuboidRegion class will now queue blocks in layers for a chunk before moving onto the next chunk. This results in higher cache hits for history enabled queues. It also allows the block placer to start earlier during preprocessing with edits affecting > 64 (configurable) chunks. Note: with history on disk enabled, this means near unlimited sized edits (for certain commands) might be feasible.
This commit is contained in:
parent
caa0e475ad
commit
5097f0cf63
@ -3,13 +3,10 @@ package com.boydti.fawe.bukkit.v0;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
@ -28,6 +25,7 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
* Map of chunks in the queue
|
||||
*/
|
||||
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
|
||||
private ArrayDeque<FaweChunk<Chunk>> chunks = new ArrayDeque<>();
|
||||
|
||||
public BukkitQueue_0(String world) {
|
||||
super(world);
|
||||
@ -41,7 +39,10 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int x, int z) {
|
||||
return Bukkit.getWorld(world).isChunkLoaded(x, z);
|
||||
if (bukkitWorld == null) {
|
||||
bukkitWorld = Bukkit.getServer().getWorld(world);
|
||||
}
|
||||
return bukkitWorld.isChunkLoaded(x, z);
|
||||
// long id = ((long) x << 32) | (z & 0xFFFFFFFFL);
|
||||
// HashSet<Long> map = this.loaded.get(world);
|
||||
// if (map != null) {
|
||||
@ -67,6 +68,7 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
result.addTask(runnable);
|
||||
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
|
||||
if (previous == null) {
|
||||
chunks.add(result);
|
||||
return;
|
||||
}
|
||||
this.blocks.put(pair, previous);
|
||||
@ -87,6 +89,7 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
result.setBlock(x & 15, y, z & 15, id, data);
|
||||
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
|
||||
if (previous == null) {
|
||||
chunks.add(result);
|
||||
return true;
|
||||
}
|
||||
this.blocks.put(pair, previous);
|
||||
@ -106,6 +109,8 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
if (previous != null) {
|
||||
this.blocks.put(pair, previous);
|
||||
result = previous;
|
||||
} else {
|
||||
chunks.add(result);
|
||||
}
|
||||
}
|
||||
result.setBiome(x & 15, z & 15, biome);
|
||||
@ -118,18 +123,23 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
if (this.blocks.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
Iterator<Entry<Long, FaweChunk<Chunk>>> iter = this.blocks.entrySet().iterator();
|
||||
FaweChunk<Chunk> toReturn = iter.next().getValue();
|
||||
if (SetQueue.IMP.isWaiting()) {
|
||||
return null;
|
||||
synchronized (blocks) {
|
||||
FaweChunk<Chunk> chunk = chunks.poll();
|
||||
if (chunk != null) {
|
||||
blocks.remove(chunk.longHash());
|
||||
this.execute(chunk);
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
iter.remove();
|
||||
this.execute(toReturn);
|
||||
return toReturn;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return chunks.size();
|
||||
}
|
||||
|
||||
private ArrayDeque<FaweChunk<Chunk>> toUpdate = new ArrayDeque<>();
|
||||
@ -156,7 +166,11 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
|
||||
@Override
|
||||
public void setChunk(FaweChunk<?> chunk) {
|
||||
this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
|
||||
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
|
||||
if (previous != null) {
|
||||
chunks.remove(previous);
|
||||
}
|
||||
chunks.add((FaweChunk<Chunk>) chunk);
|
||||
}
|
||||
|
||||
public abstract Collection<FaweChunk<Chunk>> sendChunk(Collection<FaweChunk<Chunk>> fcs);
|
||||
|
@ -155,6 +155,9 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
|
||||
} else if (cy == lcy) {
|
||||
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
|
||||
}
|
||||
if (lc == null) {
|
||||
return 0;
|
||||
}
|
||||
Object storage = ((Object[]) fieldSections.of(lc).get())[cy];
|
||||
if (storage == null) {
|
||||
ls = null;
|
||||
|
@ -149,6 +149,9 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 {
|
||||
}
|
||||
lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call());
|
||||
}
|
||||
if (lc == null) {
|
||||
return 0;
|
||||
}
|
||||
int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15));
|
||||
return ((combined & 4095) << 4) + (combined >> 12);
|
||||
}
|
||||
|
@ -42,13 +42,13 @@ public class FaweAPI {
|
||||
}
|
||||
|
||||
public static void fixLighting(String world, int x, int z, final boolean fixAll) {
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(world);
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(world, false);
|
||||
queue.fixLighting(queue.getChunk(x, z), fixAll);
|
||||
}
|
||||
|
||||
|
||||
public static void fixLighting(final Chunk chunk, final boolean fixAll) {
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName());
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName(), false);
|
||||
queue.fixLighting(queue.getChunk(chunk.getX(), chunk.getZ()), fixAll);
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ public class FaweAPI {
|
||||
tagMap = null;
|
||||
tag = null;
|
||||
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world);
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
final int yy = y_offset + y;
|
||||
|
@ -27,6 +27,9 @@ public class Settings {
|
||||
public static int CHUNK_WAIT = 0;
|
||||
public static boolean REGION_RESTRICTIONS = true;
|
||||
public static int ALLOCATE = 0;
|
||||
public static int QUEUE_SIZE = 64;
|
||||
public static int QUEUE_MAX_WAIT = 1000;
|
||||
public static int QUEUE_DISCARD_AFTER = 60000;
|
||||
|
||||
public static HashMap<String, FaweLimit> limits;
|
||||
|
||||
@ -73,6 +76,9 @@ public class Settings {
|
||||
options.put("history.buffer-size", BUFFER_SIZE);
|
||||
options.put("region-restrictions", REGION_RESTRICTIONS);
|
||||
options.put("queue.extra-time-ms", ALLOCATE);
|
||||
options.put("queue.target-size", QUEUE_SIZE);
|
||||
options.put("queue.max-wait-ms", QUEUE_MAX_WAIT);
|
||||
options.put("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
|
||||
options.put("metrics", METRICS);
|
||||
|
||||
// Default limit
|
||||
@ -85,8 +91,6 @@ public class Settings {
|
||||
FaweLimit limit = new FaweLimit();
|
||||
limit.load(config.getConfigurationSection("limits." + key), defaultLimit, false);
|
||||
}
|
||||
|
||||
|
||||
for (final Entry<String, Object> node : options.entrySet()) {
|
||||
if (!config.contains(node.getKey())) {
|
||||
config.set(node.getKey(), node.getValue());
|
||||
@ -104,6 +108,9 @@ public class Settings {
|
||||
BUFFER_SIZE = config.getInt("history.buffer-size", BUFFER_SIZE);
|
||||
CHUNK_WAIT = config.getInt("history.chunk-wait-ms");
|
||||
ALLOCATE = config.getInt("queue.extra-time-ms");
|
||||
QUEUE_SIZE = config.getInt("queue.target-size");
|
||||
QUEUE_MAX_WAIT = config.getInt("queue.max-wait-ms");
|
||||
QUEUE_DISCARD_AFTER = config.getInt("queue.discard-after-ms");
|
||||
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
|
||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ public abstract class FaweQueue {
|
||||
|
||||
public abstract int getCombinedId4Data(int x, int y, int z);
|
||||
|
||||
public abstract int size();
|
||||
|
||||
public void enqueue() {
|
||||
SetQueue.IMP.enqueue(this);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import com.boydti.fawe.object.FaweChunk;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class SetQueue {
|
||||
|
||||
@ -15,19 +14,15 @@ public class SetQueue {
|
||||
*/
|
||||
public static final SetQueue IMP = new SetQueue();
|
||||
|
||||
public final ArrayDeque<FaweQueue> queues;
|
||||
public final ArrayDeque<FaweQueue> activeQueues;
|
||||
public final ArrayDeque<FaweQueue> inactiveQueues;
|
||||
|
||||
/**
|
||||
* Track the time in ticks
|
||||
*/
|
||||
private final AtomicInteger time_waiting = new AtomicInteger(2);
|
||||
private final AtomicInteger time_current = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server
|
||||
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server
|
||||
*/
|
||||
private long last;
|
||||
private long last2;
|
||||
private long secondLast;
|
||||
private long lastSuccess;
|
||||
|
||||
/**
|
||||
* A queue of tasks that will run when the queue is empty
|
||||
@ -36,7 +31,8 @@ public class SetQueue {
|
||||
|
||||
|
||||
public SetQueue() {
|
||||
queues = new ArrayDeque();
|
||||
activeQueues = new ArrayDeque();
|
||||
inactiveQueues = new ArrayDeque<>();
|
||||
TaskManager.IMP.repeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -52,51 +48,84 @@ public class SetQueue {
|
||||
if (SetQueue.this.forceChunkSet()) {
|
||||
System.gc();
|
||||
} else {
|
||||
SetQueue.this.time_current.incrementAndGet();
|
||||
SetQueue.this.tasks();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
final long free = Settings.ALLOCATE + 50 + Math.min((50 + SetQueue.this.last) - (SetQueue.this.last = System.currentTimeMillis()), SetQueue.this.last2 - System.currentTimeMillis());
|
||||
SetQueue.this.time_current.incrementAndGet();
|
||||
final long free = Settings.ALLOCATE + 50 + Math.min((50 + SetQueue.this.last) - (SetQueue.this.last = System.currentTimeMillis()), SetQueue.this.secondLast - System.currentTimeMillis());
|
||||
do {
|
||||
if (SetQueue.this.isWaiting()) {
|
||||
return;
|
||||
}
|
||||
final FaweChunk<?> current = next();
|
||||
if (current == null) {
|
||||
SetQueue.this.time_waiting.set(Math.max(SetQueue.this.time_waiting.get(), SetQueue.this.time_current.get() - 2));
|
||||
lastSuccess = last;
|
||||
SetQueue.this.tasks();
|
||||
return;
|
||||
}
|
||||
} while (((SetQueue.this.last2 = System.currentTimeMillis()) - SetQueue.this.last) < free);
|
||||
SetQueue.this.time_waiting.set(SetQueue.this.time_current.get() - 1);
|
||||
} while (((SetQueue.this.secondLast = System.currentTimeMillis()) - SetQueue.this.last) < free);
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public void enqueue(FaweQueue queue) {
|
||||
queues.add(queue);
|
||||
inactiveQueues.remove(queue);
|
||||
activeQueues.add(queue);
|
||||
}
|
||||
|
||||
public List<FaweQueue> getQueues() {
|
||||
return new ArrayList<>(queues);
|
||||
return new ArrayList<>(activeQueues);
|
||||
}
|
||||
|
||||
public FaweQueue getNewQueue(String world) {
|
||||
return Fawe.imp().getNewQueue(world);
|
||||
public FaweQueue getNewQueue(String world, boolean autoqueue) {
|
||||
FaweQueue queue = Fawe.imp().getNewQueue(world);
|
||||
if (autoqueue) {
|
||||
inactiveQueues.add(queue);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
public FaweChunk<?> next() {
|
||||
while (queues.size() > 0) {
|
||||
FaweQueue queue = queues.poll();
|
||||
while (activeQueues.size() > 0) {
|
||||
FaweQueue queue = activeQueues.poll();
|
||||
final FaweChunk<?> set = queue.next();
|
||||
if (set != null) {
|
||||
queues.add(queue);
|
||||
activeQueues.add(queue);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
if (inactiveQueues.size() > 0) {
|
||||
ArrayList<FaweQueue> tmp = new ArrayList<>(inactiveQueues);
|
||||
if (Settings.QUEUE_MAX_WAIT != -1) {
|
||||
long now = System.currentTimeMillis();
|
||||
long diff = now - lastSuccess;
|
||||
if (diff > Settings.QUEUE_MAX_WAIT) {
|
||||
for (FaweQueue queue : tmp) {
|
||||
FaweChunk result = queue.next();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (diff > Settings.QUEUE_DISCARD_AFTER) {
|
||||
// These edits never finished
|
||||
inactiveQueues.clear();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (Settings.QUEUE_SIZE != -1) {
|
||||
int total = 0;
|
||||
for (FaweQueue queue : tmp) {
|
||||
total += queue.size();
|
||||
}
|
||||
if (total > Settings.QUEUE_SIZE) {
|
||||
for (FaweQueue queue : tmp) {
|
||||
FaweChunk result = queue.next();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -104,16 +133,8 @@ public class SetQueue {
|
||||
return next() != null;
|
||||
}
|
||||
|
||||
public boolean isWaiting() {
|
||||
return this.time_waiting.get() >= this.time_current.get();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return (this.time_waiting.get() + 1) < this.time_current.get();
|
||||
}
|
||||
|
||||
public void setWaiting() {
|
||||
this.time_waiting.set(this.time_current.get() + 1);
|
||||
return activeQueues.size() == 0 && inactiveQueues.size() == 0;
|
||||
}
|
||||
|
||||
public boolean addTask(final Runnable whenDone) {
|
||||
|
@ -232,7 +232,7 @@ public class EditSession implements Extent {
|
||||
}
|
||||
final Actor actor = event.getActor();
|
||||
|
||||
this.queue = SetQueue.IMP.getNewQueue(world.getName());
|
||||
this.queue = SetQueue.IMP.getNewQueue(world.getName(), true);
|
||||
this.world = (world = new WorldWrapper((AbstractWorld) world));
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
// Not a player; bypass history
|
||||
|
@ -348,36 +348,62 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
private Vector min = getMinimumPoint();
|
||||
private Vector max = getMaximumPoint();
|
||||
|
||||
int minX = min.getBlockX();
|
||||
int minY = min.getBlockY();
|
||||
int minZ = min.getBlockZ();
|
||||
int bx = min.getBlockX();
|
||||
int by = min.getBlockY();
|
||||
int bz = min.getBlockZ();
|
||||
|
||||
int maxX = max.getBlockX();
|
||||
int maxY = max.getBlockY();
|
||||
int maxZ = max.getBlockZ();
|
||||
int tx = max.getBlockX();
|
||||
int ty = max.getBlockY();
|
||||
int tz = max.getBlockZ();
|
||||
|
||||
private int nextX = min.getBlockX();
|
||||
private int nextY = min.getBlockY();
|
||||
private int nextZ = min.getBlockZ();
|
||||
private int x = min.getBlockX();
|
||||
private int y = min.getBlockY();
|
||||
private int z = min.getBlockZ();
|
||||
|
||||
int cx = x >> 4;
|
||||
int cz = z >> 4;
|
||||
int cbx = Math.max(bx, cx << 4);
|
||||
int cbz = Math.max(bz, cz << 4);
|
||||
int ctx = Math.min(tx, 15 + (cx << 4));
|
||||
int ctz = Math.min(tz, 15 + (cz << 4));
|
||||
|
||||
public boolean hasNext = true;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (nextX != Integer.MIN_VALUE);
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector next() {
|
||||
if (!hasNext()) throw new java.util.NoSuchElementException();
|
||||
v.x = nextX;
|
||||
v.y = nextY;
|
||||
v.z = nextZ;
|
||||
if (++nextX > maxX) {
|
||||
nextX = minX;
|
||||
if (++nextY > maxY) {
|
||||
nextY = minY;
|
||||
if (++nextZ > maxZ) {
|
||||
nextX = Integer.MIN_VALUE;
|
||||
v.x = x;
|
||||
v.y = y;
|
||||
v.z = z;
|
||||
if (++x > ctx) {
|
||||
if (++z > ctz) {
|
||||
if (++y > ty) {
|
||||
y = by;
|
||||
if (x > tx) {
|
||||
x = bx;
|
||||
if (z > tz) {
|
||||
hasNext = false;
|
||||
return v;
|
||||
}
|
||||
} else {
|
||||
z = cbz;
|
||||
}
|
||||
cx = x >> 4;
|
||||
cz = z >> 4;
|
||||
cbx = Math.max(bx, cx << 4);
|
||||
cbz = Math.max(bz, cz << 4);
|
||||
ctx = Math.min(tx, 15 + (cx << 4));
|
||||
ctz = Math.min(tz, 15 + (cz << 4));
|
||||
} else {
|
||||
x = cbx;
|
||||
z = cbz;
|
||||
}
|
||||
} else {
|
||||
x = cbx;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
|
@ -2,12 +2,9 @@ package com.boydti.fawe.forge.v0;
|
||||
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.world.Chunk;
|
||||
@ -22,6 +19,7 @@ public abstract class SpongeQueue_0 extends FaweQueue {
|
||||
* Map of chunks in the queue
|
||||
*/
|
||||
private final ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
|
||||
private ArrayDeque<FaweChunk<Chunk>> chunks = new ArrayDeque<>();
|
||||
|
||||
public SpongeQueue_0(String world) {
|
||||
super(world);
|
||||
@ -43,6 +41,7 @@ public abstract class SpongeQueue_0 extends FaweQueue {
|
||||
result.addTask(runnable);
|
||||
final FaweChunk<Chunk> previous = this.blocks.put(pair, result);
|
||||
if (previous == null) {
|
||||
chunks.add(result);
|
||||
return;
|
||||
}
|
||||
this.blocks.put(pair, previous);
|
||||
@ -63,6 +62,7 @@ public abstract class SpongeQueue_0 extends FaweQueue {
|
||||
result.setBlock(x & 15, y, z & 15, id, data);
|
||||
final FaweChunk<Chunk> previous = this.blocks.put(pair, result);
|
||||
if (previous == null) {
|
||||
chunks.add(result);
|
||||
return true;
|
||||
}
|
||||
this.blocks.put(pair, previous);
|
||||
@ -94,18 +94,23 @@ public abstract class SpongeQueue_0 extends FaweQueue {
|
||||
if (this.blocks.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
final Iterator<Map.Entry<Long, FaweChunk<Chunk>>> iter = this.blocks.entrySet().iterator();
|
||||
final FaweChunk<Chunk> toReturn = iter.next().getValue();
|
||||
if (SetQueue.IMP.isWaiting()) {
|
||||
return null;
|
||||
synchronized (blocks) {
|
||||
FaweChunk<Chunk> chunk = chunks.poll();
|
||||
if (chunk != null) {
|
||||
blocks.remove(chunk.longHash());
|
||||
this.execute(chunk);
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
iter.remove();
|
||||
this.execute(toReturn);
|
||||
return toReturn;
|
||||
} catch (final Throwable e) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return chunks.size();
|
||||
}
|
||||
|
||||
private final ArrayDeque<FaweChunk<Chunk>> toUpdate = new ArrayDeque<>();
|
||||
@ -132,7 +137,11 @@ public abstract class SpongeQueue_0 extends FaweQueue {
|
||||
|
||||
@Override
|
||||
public void setChunk(final FaweChunk<?> chunk) {
|
||||
this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
|
||||
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
|
||||
if (previous != null) {
|
||||
chunks.remove(previous);
|
||||
}
|
||||
chunks.add((FaweChunk<Chunk>) chunk);
|
||||
}
|
||||
|
||||
public abstract Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs);
|
||||
|
Loading…
Reference in New Issue
Block a user