From e2a63ee3612b5ac405811c0004b148b7bc01805c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jun 2022 17:05:30 +0100 Subject: [PATCH] Consider latency when getting next send time from DB. --- .../bramble/api/db/DatabaseComponent.java | 13 +++-- .../org/briarproject/bramble/db/Database.java | 11 +++-- .../bramble/db/DatabaseComponentImpl.java | 6 +-- .../briarproject/bramble/db/JdbcDatabase.java | 20 +++++++- .../bramble/sync/DuplexOutgoingSession.java | 6 ++- .../bramble/db/JdbcDatabaseTest.java | 47 +++++++++++++------ 6 files changed, 72 insertions(+), 31 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index a934fa6c8..c28c07fe9 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -541,15 +541,18 @@ public interface DatabaseComponent extends TransactionManager { */ long getNextCleanupDeadline(Transaction txn) throws DbException; - /* + /** * Returns the next time (in milliseconds since the Unix epoch) when a - * message is due to be sent to the given contact. The returned value may - * be zero if a message is due to be sent immediately, or Long.MAX_VALUE if - * no messages are scheduled to be sent. + * message is due to be sent to the given contact over a transport with + * the given latency. + *

+ * The returned value may be zero if a message is due to be sent + * immediately, or Long.MAX_VALUE if no messages are scheduled to be sent. *

* Read-only. */ - long getNextSendTime(Transaction txn, ContactId c) throws DbException; + long getNextSendTime(Transaction txn, ContactId c, long maxLatency) + throws DbException; /** * Returns the pending contact with the given ID. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 1e6f4ab31..1e53c1fe2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -587,13 +587,16 @@ interface Database { /** * Returns the next time (in milliseconds since the Unix epoch) when a - * message is due to be sent to the given contact. The returned value may - * be zero if a message is due to be sent immediately, or Long.MAX_VALUE - * if no messages are scheduled to be sent. + * message is due to be sent to the given contact over a transport with + * the given latency. + *

+ * The returned value may be zero if a message is due to be sent + * immediately, or Long.MAX_VALUE if no messages are scheduled to be sent. *

* Read-only. */ - long getNextSendTime(T txn, ContactId c) throws DbException; + long getNextSendTime(T txn, ContactId c, long maxLatency) + throws DbException; /** * Returns the pending contact with the given ID. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index 14b033b41..cfc20ecce 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -814,10 +814,10 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public long getNextSendTime(Transaction transaction, ContactId c) - throws DbException { + public long getNextSendTime(Transaction transaction, ContactId c, + long maxLatency) throws DbException { T txn = unbox(transaction); - return db.getNextSendTime(txn, c); + return db.getNextSendTime(txn, c, maxLatency); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index bf23fd683..9dc143bfa 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -2490,12 +2490,28 @@ abstract class JdbcDatabase implements Database { } @Override - public long getNextSendTime(Connection txn, ContactId c) + public long getNextSendTime(Connection txn, ContactId c, long maxLatency) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT expiry FROM statuses" + // Are any messages sendable immediately? + String sql = "SELECT NULL FROM statuses" + + " WHERE contactId = ? AND state = ?" + + " AND groupShared = TRUE AND messageShared = TRUE" + + " AND deleted = FALSE AND seen = FALSE" + + " AND (maxLatency IS NULL OR ? < maxLatency)"; + ps = txn.prepareStatement(sql); + ps.setInt(1, c.getInt()); + ps.setInt(2, DELIVERED.getValue()); + ps.setLong(3, maxLatency); + rs = ps.executeQuery(); + boolean found = rs.next(); + rs.close(); + ps.close(); + if (found) return 0; + // When is the earliest expiry time (could be in the past)? + sql = "SELECT expiry FROM statuses" + " WHERE contactId = ? AND state = ?" + " AND groupShared = TRUE AND messageShared = TRUE" + " AND deleted = FALSE AND seen = FALSE" diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java index 4bfb17bb0..3dc74bd19 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java @@ -313,7 +313,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener { Collection batch = db.generateRequestedBatch(txn, contactId, BATCH_CAPACITY, maxLatency); - setNextSendTime(db.getNextSendTime(txn, contactId)); + setNextSendTime(db.getNextSendTime(txn, contactId, + maxLatency)); return batch; }); if (LOG.isLoggable(INFO)) @@ -356,7 +357,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener { Offer o = db.transactionWithNullableResult(false, txn -> { Offer offer = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS, maxLatency); - setNextSendTime(db.getNextSendTime(txn, contactId)); + setNextSendTime(db.getNextSendTime(txn, contactId, + maxLatency)); return offer; }); if (LOG.isLoggable(INFO)) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 54d19da0d..35e091df3 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -2020,37 +2020,51 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.addMessage(txn, message, UNKNOWN, false, false, null); // There should be no messages to send - assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId)); + assertEquals(Long.MAX_VALUE, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Share the group with the contact - still no messages to send db.addGroupVisibility(txn, contactId, groupId, true); - assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId)); + assertEquals(Long.MAX_VALUE, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Set the message's state to DELIVERED - still no messages to send db.setMessageState(txn, messageId, DELIVERED); - assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId)); + assertEquals(Long.MAX_VALUE, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Share the message - now it should be sendable immediately db.setMessageShared(txn, messageId, true); - assertEquals(0, db.getNextSendTime(txn, contactId)); + assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Mark the message as requested - it should still be sendable db.raiseRequestedFlag(txn, contactId, messageId); - assertEquals(0, db.getNextSendTime(txn, contactId)); + assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Update the message's expiry time as though we sent it - now the // message should be sendable after one round-trip - db.updateRetransmissionData(txn, contactId, messageId, 1000); - assertEquals(now + 2000, db.getNextSendTime(txn, contactId)); + db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY); + assertEquals(now + MAX_LATENCY * 2, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); + + // The message should be sendable immediately over a transport with + // lower latency + assertEquals(0L, db.getNextSendTime(txn, contactId, MAX_LATENCY - 1)); // Update the message's expiry time again - now it should be sendable // after two round-trips - db.updateRetransmissionData(txn, contactId, messageId, 1000); - assertEquals(now + 4000, db.getNextSendTime(txn, contactId)); + db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY); + assertEquals(now + MAX_LATENCY * 4, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); + + // The message should be sendable immediately over a transport with + // lower latency + assertEquals(0L, db.getNextSendTime(txn, contactId, MAX_LATENCY - 1)); // Delete the message - there should be no messages to send db.deleteMessage(txn, messageId); - assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId)); + assertEquals(Long.MAX_VALUE, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); db.commitTransaction(txn); db.close(); @@ -2115,7 +2129,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY); // The message should expire after 2 * MAX_LATENCY - assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId)); + assertEquals(now + MAX_LATENCY * 2, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Time: now + MAX_LATENCY * 2 - 1 // The message should not yet be sendable @@ -2158,7 +2173,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY); // The message should expire after 2 * MAX_LATENCY - assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId)); + assertEquals(now + MAX_LATENCY * 2, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // The message should not be sendable via the same transport ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY); @@ -2205,7 +2221,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY); // The message should expire after 2 * MAX_LATENCY - assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId)); + assertEquals(now + MAX_LATENCY * 2, + db.getNextSendTime(txn, contactId, MAX_LATENCY)); // Time: now + MAX_LATENCY * 2 - 1 // The message should not yet be sendable @@ -2216,8 +2233,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Reset the retransmission times db.resetUnackedMessagesToSend(txn, contactId); - // The message should have infinitely short expiry - assertEquals(0, db.getNextSendTime(txn, contactId)); + // The message should be sendable immediately + assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY)); // The message should be sendable ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);