first commit
This commit is contained in:
commit
cc02c053dd
60
.gitignore
vendored
Normal file
60
.gitignore
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/*.*
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
cmake-build-release/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
filequeue.iml
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
/.idea/
|
||||||
|
target/
|
||||||
|
.DS_Store
|
||||||
|
/.idea/
|
||||||
|
/.idea/
|
49
pom.xml
Normal file
49
pom.xml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<groupId>it.cavallium</groupId>
|
||||||
|
<artifactId>filequeue</artifactId>
|
||||||
|
<name>file queue project</name>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Light weight, high performance, simple, reliable and persistent queue</description>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
</properties>
|
||||||
|
<distributionManagement>
|
||||||
|
<repository>
|
||||||
|
<id>mchv-release-distribution</id>
|
||||||
|
<name>MCHV Release Apache Maven Packages Distribution</name>
|
||||||
|
<url>https://mvn.mchv.eu/repository/mchv</url>
|
||||||
|
</repository>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>mchv-snapshot-distribution</id>
|
||||||
|
<name>MCHV Snapshot Apache Maven Packages Distribution</name>
|
||||||
|
<url>https://mvn.mchv.eu/repository/mchv-snapshot</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
</distributionManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>11</source>
|
||||||
|
<target>11</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.tape2</groupId>
|
||||||
|
<artifactId>tape</artifactId>
|
||||||
|
<version>2.0.0-beta1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
22
src/main/java/it/cavallium/filequeue/Deserializer.java
Normal file
22
src/main/java/it/cavallium/filequeue/Deserializer.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface Deserializer<T> {
|
||||||
|
|
||||||
|
default T deserialize(byte[] data) throws IOException {
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||||
|
return deserialize(data.length, new DataInputStream(bais));
|
||||||
|
}
|
||||||
|
|
||||||
|
default T deserialize(int length, DataInput dataInput) throws IOException {
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
dataInput.readFully(data);
|
||||||
|
return deserialize(data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import com.squareup.tape2.QueueFile;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public final class DiskQueueToConsumer<T> implements IQueueToConsumer<T> {
|
||||||
|
|
||||||
|
private final QueueToConsumer<T> queue;
|
||||||
|
private final QueueFile queueFile;
|
||||||
|
|
||||||
|
public DiskQueueToConsumer(Path file,
|
||||||
|
Serializer<T> serializer,
|
||||||
|
Deserializer<T> deserializer,
|
||||||
|
QueueConsumer<T> consumer) throws IOException {
|
||||||
|
QueueFile queueFile = new QueueFile.Builder(file.toFile()).build();
|
||||||
|
this.queueFile = queueFile;
|
||||||
|
this.queue = new QueueToConsumer<>(new SimpleQueueFile<>(queueFile, serializer, deserializer), consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(T value) {
|
||||||
|
queue.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
queue.close();
|
||||||
|
try {
|
||||||
|
queueFile.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startQueue() {
|
||||||
|
queue.startQueue();
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/it/cavallium/filequeue/IQueueToConsumer.java
Normal file
13
src/main/java/it/cavallium/filequeue/IQueueToConsumer.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
public interface IQueueToConsumer<T> extends Closeable {
|
||||||
|
|
||||||
|
void add(T value);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void startQueue();
|
||||||
|
}
|
6
src/main/java/it/cavallium/filequeue/QueueConsumer.java
Normal file
6
src/main/java/it/cavallium/filequeue/QueueConsumer.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
public interface QueueConsumer<T> {
|
||||||
|
|
||||||
|
boolean tryConsume(T value);
|
||||||
|
}
|
93
src/main/java/it/cavallium/filequeue/QueueToConsumer.java
Normal file
93
src/main/java/it/cavallium/filequeue/QueueToConsumer.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
|
class QueueToConsumer<T> implements IQueueToConsumer<T> {
|
||||||
|
|
||||||
|
private final long BACKOFF_NS = Duration.ofMillis(2).toNanos();
|
||||||
|
private final long MAX_BACKOFF_NS = Duration.ofMillis(500).toNanos();
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private final Semaphore semaphore = new Semaphore(0);
|
||||||
|
private long queued;
|
||||||
|
private final SimpleQueue<T> queue;
|
||||||
|
private final QueueConsumer<T> consumer;
|
||||||
|
private Manager manager;
|
||||||
|
private volatile boolean closed;
|
||||||
|
|
||||||
|
public QueueToConsumer(SimpleQueue<T> queue, QueueConsumer<T> consumer) {
|
||||||
|
this.queue = queue;
|
||||||
|
this.consumer = consumer;
|
||||||
|
queued = queue.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void startQueue() {
|
||||||
|
if (manager == null) {
|
||||||
|
this.manager = new Manager();
|
||||||
|
manager.setName("queue-manager");
|
||||||
|
manager.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(T value) {
|
||||||
|
boolean shouldAdd = true;
|
||||||
|
synchronized (lock) {
|
||||||
|
if (queued == 0 && consumer.tryConsume(value)) {
|
||||||
|
shouldAdd = false;
|
||||||
|
} else {
|
||||||
|
queued++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldAdd && !closed) {
|
||||||
|
synchronized (queue) {
|
||||||
|
queue.add(value);
|
||||||
|
}
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
closed = true;
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Manager extends Thread {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while (!closed) {
|
||||||
|
boolean shouldRemove = false;
|
||||||
|
T element;
|
||||||
|
synchronized (lock) {
|
||||||
|
if (queued > 0) {
|
||||||
|
queued--;
|
||||||
|
shouldRemove = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
semaphore.acquire();
|
||||||
|
if (!closed && shouldRemove) {
|
||||||
|
synchronized (queue) {
|
||||||
|
element = queue.remove();
|
||||||
|
}
|
||||||
|
long nextDelay = BACKOFF_NS;
|
||||||
|
while (!closed && !consumer.tryConsume(element)) {
|
||||||
|
LockSupport.parkNanos(nextDelay);
|
||||||
|
if (nextDelay + BACKOFF_NS <= MAX_BACKOFF_NS) {
|
||||||
|
nextDelay += BACKOFF_NS;
|
||||||
|
} else if (nextDelay < MAX_BACKOFF_NS) {
|
||||||
|
nextDelay = MAX_BACKOFF_NS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
src/main/java/it/cavallium/filequeue/Serializer.java
Normal file
22
src/main/java/it/cavallium/filequeue/Serializer.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface Serializer<T> {
|
||||||
|
|
||||||
|
default byte[] serialize(T data) throws IOException {
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
|
try (DataOutputStream daos = new DataOutputStream(baos)) {
|
||||||
|
serialize(data, daos);
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void serialize(T data, DataOutput output) throws IOException {
|
||||||
|
output.write(serialize(data));
|
||||||
|
}
|
||||||
|
}
|
10
src/main/java/it/cavallium/filequeue/SimpleQueue.java
Normal file
10
src/main/java/it/cavallium/filequeue/SimpleQueue.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
interface SimpleQueue<T> {
|
||||||
|
|
||||||
|
void add(T element);
|
||||||
|
|
||||||
|
T remove();
|
||||||
|
|
||||||
|
int size();
|
||||||
|
}
|
47
src/main/java/it/cavallium/filequeue/SimpleQueueFile.java
Normal file
47
src/main/java/it/cavallium/filequeue/SimpleQueueFile.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import com.squareup.tape2.QueueFile;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
class SimpleQueueFile<T> implements SimpleQueue<T> {
|
||||||
|
|
||||||
|
private final QueueFile queueFile;
|
||||||
|
private final Serializer<T> ser;
|
||||||
|
private final Deserializer<T> des;
|
||||||
|
|
||||||
|
public SimpleQueueFile(QueueFile queueFile, Serializer<T> serializer, Deserializer<T> deserializer) {
|
||||||
|
this.queueFile = queueFile;
|
||||||
|
this.ser = serializer;
|
||||||
|
this.des = deserializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(T element) {
|
||||||
|
try {
|
||||||
|
queueFile.add(ser.serialize(element));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T remove() {
|
||||||
|
try {
|
||||||
|
byte[] element = queueFile.peek();
|
||||||
|
if (element == null) {
|
||||||
|
throw new NoSuchElementException("Queue is empty");
|
||||||
|
}
|
||||||
|
var deserialized = des.deserialize(element);
|
||||||
|
queueFile.remove();
|
||||||
|
return deserialized;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return queueFile.size();
|
||||||
|
}
|
||||||
|
}
|
27
src/main/java/it/cavallium/filequeue/SimpleQueueJava.java
Normal file
27
src/main/java/it/cavallium/filequeue/SimpleQueueJava.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package it.cavallium.filequeue;
|
||||||
|
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
class SimpleQueueJava<T> implements SimpleQueue<T> {
|
||||||
|
|
||||||
|
private final Queue<T> queue;
|
||||||
|
|
||||||
|
public SimpleQueueJava(Queue<T> queue) {
|
||||||
|
this.queue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(T element) {
|
||||||
|
queue.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T remove() {
|
||||||
|
return queue.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return queue.size();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user