Skip to content

Commit bed66e9

Browse files
committed
Reworked LimitedDecayQueue
1 parent 07b4f41 commit bed66e9

File tree

2 files changed

+69
-11
lines changed

2 files changed

+69
-11
lines changed

common/src/main/kotlin/com/lambda/module/modules/network/PacketLimiter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ object PacketLimiter : Module(
4141
}
4242
private val interval by setting("Duration", 1000L, 1L..1000L, 50L, "The interval / duration in milliseconds to limit packets for", unit = " ms").apply {
4343
onValueChange { _, to ->
44-
packetQueue.setInterval(to)
44+
packetQueue.setDecayTime(to)
4545
}
4646
}
4747

common/src/main/kotlin/com/lambda/util/collections/LimitedDecayQueue.kt

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,33 @@ package com.lambda.util.collections
2020
import java.time.Instant
2121
import java.util.concurrent.ConcurrentLinkedQueue
2222

23+
/**
24+
* A thread-safe collection that limits the number of elements it can hold and automatically removes elements
25+
* older than a specified time interval. The elements are stored with the timestamp of their addition to the collection.
26+
*
27+
* @param E The type of elements held in this collection.
28+
* @property sizeLimit The maximum number of elements the queue can hold at any given time.
29+
* @property maxAge The age (in milliseconds) after which elements are considered expired and are removed from the queue.
30+
*/
2331
class LimitedDecayQueue<E>(
2432
private var sizeLimit: Int,
25-
private var interval: Long,
26-
) {
33+
private var maxAge: Long,
34+
) : AbstractMutableCollection<E>() {
2735
private val queue: ConcurrentLinkedQueue<Pair<E, Instant>> = ConcurrentLinkedQueue()
2836

29-
val size: Int
30-
get() = queue.size
37+
override val size: Int
38+
get() {
39+
cleanUp()
40+
return queue.size
41+
}
42+
43+
override fun iterator(): MutableIterator<E> {
44+
cleanUp()
45+
return queue.map { it.first }.iterator() as MutableIterator<E>
46+
}
3147

3248
@Synchronized
33-
fun add(element: E): Boolean {
49+
override fun add(element: E): Boolean {
3450
cleanUp()
3551
return if (queue.size < sizeLimit) {
3652
queue.add(element to Instant.now())
@@ -41,21 +57,63 @@ class LimitedDecayQueue<E>(
4157
}
4258

4359
@Synchronized
44-
fun setMaxSize(newSize: Int) {
45-
sizeLimit = newSize
60+
override fun addAll(elements: Collection<E>): Boolean {
61+
cleanUp()
62+
val spaceAvailable = sizeLimit - queue.size
63+
val elementsToAdd = elements.take(spaceAvailable)
64+
val added = elementsToAdd.map { queue.add(it to Instant.now()) }
65+
return added.any { it }
66+
}
67+
68+
@Synchronized
69+
override fun remove(element: E): Boolean {
70+
cleanUp()
71+
return queue.removeIf { it.first == element }
72+
}
73+
74+
@Synchronized
75+
override fun removeAll(elements: Collection<E>): Boolean {
4676
cleanUp()
77+
return queue.removeIf { it.first in elements }
4778
}
4879

4980
@Synchronized
50-
fun setInterval(newInterval: Long) {
51-
interval = newInterval
81+
override fun retainAll(elements: Collection<E>): Boolean {
5282
cleanUp()
83+
return queue.removeIf { it.first !in elements }
5384
}
5485

5586
@Synchronized
87+
override fun clear() {
88+
queue.clear()
89+
}
90+
91+
/**
92+
* Updates the maximum allowed size for the queue and triggers a cleanup operation
93+
* to remove elements exceeding the new size or falling outside the allowed time interval.
94+
*
95+
* @param newSize The new maximum size for the queue. Must be a non-negative integer.
96+
*/
97+
fun setMaxSize(newSize: Int) {
98+
sizeLimit = newSize
99+
cleanUp()
100+
}
101+
102+
/**
103+
* Sets the decay time for the elements in the queue. The decay time determines the
104+
* maximum age that any element in the queue can have before being considered expired
105+
* and removed. Updates the internal state and triggers a cleanup of expired elements.
106+
*
107+
* @param decayTime The decay time in milliseconds. Must be a non-negative value.
108+
*/
109+
fun setDecayTime(decayTime: Long) {
110+
maxAge = decayTime
111+
cleanUp()
112+
}
113+
56114
private fun cleanUp() {
57115
val now = Instant.now()
58-
while (queue.isNotEmpty() && now.minusMillis(interval).isAfter(queue.peek().second)) {
116+
while (queue.isNotEmpty() && now.minusMillis(maxAge).isAfter(queue.peek().second)) {
59117
queue.poll()
60118
}
61119
}

0 commit comments

Comments
 (0)