mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Limit the number of offered messages per contact.
Also fixed a bug in addGroup(): SELECT COUNT (NULL) doesn't work.
This commit is contained in:
@@ -220,6 +220,13 @@ interface Database<T> {
|
||||
boolean containsVisibleMessage(T txn, ContactId c, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the number of messages offered by the given contact.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
int countOfferedMessages(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the status of all groups to which the user subscribes or can
|
||||
* subscribe, excluding inbox groups.
|
||||
@@ -634,8 +641,8 @@ interface Database<T> {
|
||||
void removeMessage(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes an offered message ID that was offered by the given contact, or
|
||||
* returns false if there is no such message ID.
|
||||
* Removes an offered message that was offered by the given contact, or
|
||||
* returns false if there is no such message.
|
||||
* <p>
|
||||
* Locking: message write.
|
||||
*/
|
||||
@@ -643,7 +650,7 @@ interface Database<T> {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Removes the given offered message IDs that were offered by the given
|
||||
* Removes the given offered messages that were offered by the given
|
||||
* contact.
|
||||
* <p>
|
||||
* Locking: message write.
|
||||
|
||||
@@ -6,6 +6,7 @@ import static net.sf.briar.db.DatabaseConstants.BYTES_PER_SWEEP;
|
||||
import static net.sf.briar.db.DatabaseConstants.CRITICAL_FREE_SPACE;
|
||||
import static net.sf.briar.db.DatabaseConstants.MAX_BYTES_BETWEEN_SPACE_CHECKS;
|
||||
import static net.sf.briar.db.DatabaseConstants.MAX_MS_BETWEEN_SPACE_CHECKS;
|
||||
import static net.sf.briar.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||
import static net.sf.briar.db.DatabaseConstants.MIN_FREE_SPACE;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -1363,14 +1364,16 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
if(!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
int count = db.countOfferedMessages(txn, c);
|
||||
for(MessageId m : o.getMessageIds()) {
|
||||
if(db.containsVisibleMessage(txn, c, m)) {
|
||||
db.raiseSeenFlag(txn, c, m);
|
||||
db.raiseAckFlag(txn, c, m);
|
||||
ack = true;
|
||||
} else {
|
||||
} else if(count < MAX_OFFERED_MESSAGES) {
|
||||
db.addOfferedMessage(txn, c, m);
|
||||
request = true;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
|
||||
@@ -2,6 +2,13 @@ package net.sf.briar.db;
|
||||
|
||||
interface DatabaseConstants {
|
||||
|
||||
/**
|
||||
* The maximum number of offered messages from each contact that will be
|
||||
* stored. If offers arrive more quickly than requests can be sent and this
|
||||
* limit is reached, additional offers will not be stored.
|
||||
*/
|
||||
int MAX_OFFERED_MESSAGES = 1000;
|
||||
|
||||
// FIXME: These should be configurable
|
||||
|
||||
/**
|
||||
|
||||
@@ -668,10 +668,20 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
public boolean addGroup(Connection txn, Group g) throws DbException {
|
||||
if(maximumSubscriptionsReached(txn)) return false;
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "INSERT INTO groups"
|
||||
String sql = "SELECT COUNT (groupId) FROM groups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
int count = rs.getInt(1);
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
|
||||
if(count == MAX_SUBSCRIPTIONS) return false;
|
||||
sql = "INSERT INTO groups"
|
||||
+ " (groupId, name, salt, visibleToAll)"
|
||||
+ " VALUES (?, ?, ?, FALSE)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
@@ -682,27 +692,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
return true;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean maximumSubscriptionsReached(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT COUNT (NULL) FROM groups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
int count = rs.getInt(1);
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
|
||||
return count == MAX_SUBSCRIPTIONS;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
@@ -772,7 +761,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Limit the number of offers per contact
|
||||
public void addOfferedMessage(Connection txn, ContactId c, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1130,6 +1118,29 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public int countOfferedMessages(Connection txn, ContactId c)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT COUNT (messageId) FROM offers "
|
||||
+ " WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbException();
|
||||
int count = rs.getInt(1);
|
||||
if(rs.next()) throw new DbException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return count;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<GroupStatus> getAvailableGroups(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
|
||||
@@ -2,9 +2,9 @@ package net.sf.briar.db;
|
||||
|
||||
import static net.sf.briar.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
||||
import static net.sf.briar.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -1087,9 +1087,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
public void testReceiveOffer() throws Exception {
|
||||
final MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||
final MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||
final BitSet expectedRequest = new BitSet(3);
|
||||
expectedRequest.set(0);
|
||||
expectedRequest.set(2);
|
||||
final MessageId messageId3 = new MessageId(TestUtils.getRandomId());
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
final Database<Object> database = context.mock(Database.class);
|
||||
@@ -1101,16 +1099,25 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
will(returnValue(txn));
|
||||
oneOf(database).containsContact(txn, contactId);
|
||||
will(returnValue(true));
|
||||
// There's room for two more offered messages
|
||||
oneOf(database).countOfferedMessages(txn, contactId);
|
||||
will(returnValue(MAX_OFFERED_MESSAGES - 2));
|
||||
// The first message isn't visible - request it
|
||||
oneOf(database).containsVisibleMessage(txn, contactId, messageId);
|
||||
will(returnValue(false)); // Not visible - request message # 0
|
||||
will(returnValue(false));
|
||||
oneOf(database).addOfferedMessage(txn, contactId, messageId);
|
||||
// The second message is visible - ack it
|
||||
oneOf(database).containsVisibleMessage(txn, contactId, messageId1);
|
||||
will(returnValue(true)); // Visible - ack message # 1
|
||||
will(returnValue(true));
|
||||
oneOf(database).raiseSeenFlag(txn, contactId, messageId1);
|
||||
oneOf(database).raiseAckFlag(txn, contactId, messageId1);
|
||||
// The third message isn't visible - request it
|
||||
oneOf(database).containsVisibleMessage(txn, contactId, messageId2);
|
||||
will(returnValue(false)); // Not visible - request message # 2
|
||||
will(returnValue(false));
|
||||
oneOf(database).addOfferedMessage(txn, contactId, messageId2);
|
||||
// The fourth message isn't visible, but there's no room to store it
|
||||
oneOf(database).containsVisibleMessage(txn, contactId, messageId3);
|
||||
will(returnValue(false));
|
||||
oneOf(database).commitTransaction(txn);
|
||||
oneOf(listener).eventOccurred(with(any(MessageToAckEvent.class)));
|
||||
oneOf(listener).eventOccurred(with(any(
|
||||
@@ -1120,7 +1127,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
shutdown);
|
||||
|
||||
db.addListener(listener);
|
||||
Offer o = new Offer(Arrays.asList(messageId, messageId1, messageId2));
|
||||
Offer o = new Offer(Arrays.asList(messageId, messageId1, messageId2,
|
||||
messageId3));
|
||||
db.receiveOffer(contactId, o);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@@ -1509,6 +1509,35 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOfferedMessages() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact - initially there should be no offered messages
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
assertEquals(0, db.countOfferedMessages(txn, contactId));
|
||||
|
||||
// Add some offered messages and count them
|
||||
List<MessageId> ids = new ArrayList<MessageId>();
|
||||
for(int i = 0; i < 10; i++) {
|
||||
MessageId m = new MessageId(TestUtils.getRandomId());
|
||||
db.addOfferedMessage(txn, contactId, m);
|
||||
ids.add(m);
|
||||
}
|
||||
assertEquals(10, db.countOfferedMessages(txn, contactId));
|
||||
|
||||
// Remove some of the offered messages and count again
|
||||
List<MessageId> half = ids.subList(0, 5);
|
||||
db.removeOfferedMessages(txn, contactId, half);
|
||||
assertTrue(db.removeOfferedMessage(txn, contactId, ids.get(5)));
|
||||
assertEquals(4, db.countOfferedMessages(txn, contactId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionHandling() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
|
||||
Reference in New Issue
Block a user