mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
Limit the number of waiting database writes to avoid running out of
memory.
This commit is contained in:
@@ -3,6 +3,7 @@ package net.sf.briar.transport.batch;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ import net.sf.briar.api.transport.ConnectionReaderFactory;
|
|||||||
|
|
||||||
class IncomingBatchConnection {
|
class IncomingBatchConnection {
|
||||||
|
|
||||||
|
private static final int MAX_WAITING_DB_WRITES = 5;
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(IncomingBatchConnection.class.getName());
|
Logger.getLogger(IncomingBatchConnection.class.getName());
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ class IncomingBatchConnection {
|
|||||||
private final ConnectionContext ctx;
|
private final ConnectionContext ctx;
|
||||||
private final BatchTransportReader reader;
|
private final BatchTransportReader reader;
|
||||||
private final byte[] tag;
|
private final byte[] tag;
|
||||||
|
private final Semaphore semaphore;
|
||||||
|
|
||||||
IncomingBatchConnection(Executor executor,
|
IncomingBatchConnection(Executor executor,
|
||||||
ConnectionReaderFactory connFactory,
|
ConnectionReaderFactory connFactory,
|
||||||
@@ -45,6 +49,7 @@ class IncomingBatchConnection {
|
|||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
|
semaphore = new Semaphore(MAX_WAITING_DB_WRITES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void read() {
|
void read() {
|
||||||
@@ -59,6 +64,7 @@ class IncomingBatchConnection {
|
|||||||
if(proto.hasAck()) {
|
if(proto.hasAck()) {
|
||||||
final Ack a = proto.readAck();
|
final Ack a = proto.readAck();
|
||||||
// Store the ack on another thread
|
// Store the ack on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -67,11 +73,13 @@ class IncomingBatchConnection {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasBatch()) {
|
} else if(proto.hasBatch()) {
|
||||||
final UnverifiedBatch b = proto.readBatch();
|
final UnverifiedBatch b = proto.readBatch();
|
||||||
// Verify and store the batch on another thread
|
// Verify and store the batch on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -83,11 +91,13 @@ class IncomingBatchConnection {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasSubscriptionUpdate()) {
|
} else if(proto.hasSubscriptionUpdate()) {
|
||||||
final SubscriptionUpdate s = proto.readSubscriptionUpdate();
|
final SubscriptionUpdate s = proto.readSubscriptionUpdate();
|
||||||
// Store the update on another thread
|
// Store the update on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -96,11 +106,13 @@ class IncomingBatchConnection {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasTransportUpdate()) {
|
} else if(proto.hasTransportUpdate()) {
|
||||||
final TransportUpdate t = proto.readTransportUpdate();
|
final TransportUpdate t = proto.readTransportUpdate();
|
||||||
// Store the update on another thread
|
// Store the update on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -109,12 +121,15 @@ class IncomingBatchConnection {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
reader.dispose(false);
|
reader.dispose(false);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -49,6 +50,8 @@ import net.sf.briar.api.transport.StreamTransportConnection;
|
|||||||
|
|
||||||
abstract class StreamConnection implements DatabaseListener {
|
abstract class StreamConnection implements DatabaseListener {
|
||||||
|
|
||||||
|
private static final int MAX_WAITING_DB_WRITES = 5;
|
||||||
|
|
||||||
private static enum State { SEND_OFFER, IDLE, AWAIT_REQUEST, SEND_BATCHES };
|
private static enum State { SEND_OFFER, IDLE, AWAIT_REQUEST, SEND_BATCHES };
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -63,6 +66,8 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
protected final ContactId contactId;
|
protected final ContactId contactId;
|
||||||
protected final StreamTransportConnection connection;
|
protected final StreamTransportConnection connection;
|
||||||
|
|
||||||
|
private final Semaphore semaphore;
|
||||||
|
|
||||||
private int writerFlags = 0; // Locking: this
|
private int writerFlags = 0; // Locking: this
|
||||||
private Collection<MessageId> offered = null; // Locking: this
|
private Collection<MessageId> offered = null; // Locking: this
|
||||||
private LinkedList<MessageId> requested = null; // Locking: this
|
private LinkedList<MessageId> requested = null; // Locking: this
|
||||||
@@ -82,6 +87,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
this.protoWriterFactory = protoWriterFactory;
|
this.protoWriterFactory = protoWriterFactory;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
|
semaphore = new Semaphore(MAX_WAITING_DB_WRITES);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ConnectionReader createConnectionReader()
|
protected abstract ConnectionReader createConnectionReader()
|
||||||
@@ -126,6 +132,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(proto.hasAck()) {
|
if(proto.hasAck()) {
|
||||||
final Ack a = proto.readAck();
|
final Ack a = proto.readAck();
|
||||||
// Store the ack on another thread
|
// Store the ack on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -134,11 +141,13 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasBatch()) {
|
} else if(proto.hasBatch()) {
|
||||||
final UnverifiedBatch b = proto.readBatch();
|
final UnverifiedBatch b = proto.readBatch();
|
||||||
// Verify and store the batch on another thread
|
// Verify and store the batch on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -150,6 +159,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasOffer()) {
|
} else if(proto.hasOffer()) {
|
||||||
@@ -182,6 +192,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
// Mark the unrequested messages as seen on another thread
|
// Mark the unrequested messages as seen on another thread
|
||||||
final List<MessageId> l =
|
final List<MessageId> l =
|
||||||
Collections.unmodifiableList(seen);
|
Collections.unmodifiableList(seen);
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -190,6 +201,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Store the requested message IDs and notify the writer
|
// Store the requested message IDs and notify the writer
|
||||||
@@ -203,6 +215,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
} else if(proto.hasSubscriptionUpdate()) {
|
} else if(proto.hasSubscriptionUpdate()) {
|
||||||
final SubscriptionUpdate s = proto.readSubscriptionUpdate();
|
final SubscriptionUpdate s = proto.readSubscriptionUpdate();
|
||||||
// Store the update on another thread
|
// Store the update on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -211,11 +224,13 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if(proto.hasTransportUpdate()) {
|
} else if(proto.hasTransportUpdate()) {
|
||||||
final TransportUpdate t = proto.readTransportUpdate();
|
final TransportUpdate t = proto.readTransportUpdate();
|
||||||
// Store the update on another thread
|
// Store the update on another thread
|
||||||
|
semaphore.acquire();
|
||||||
executor.execute(new Runnable() {
|
executor.execute(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -224,6 +239,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(LOG.isLoggable(Level.WARNING))
|
if(LOG.isLoggable(Level.WARNING))
|
||||||
LOG.warning(e.getMessage());
|
LOG.warning(e.getMessage());
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -233,6 +249,8 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
connection.dispose(false);
|
connection.dispose(false);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
|
||||||
connection.dispose(false);
|
connection.dispose(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user