mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Updated javadoc and renamed type parameters.
This commit is contained in:
@@ -21,13 +21,13 @@ import net.sf.briar.api.protocol.MessageId;
|
||||
* Abstract superclass containing code shared by ReadWriteLockDatabaseComponent
|
||||
* and SynchronizedDatabaseComponent.
|
||||
*/
|
||||
abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent,
|
||||
abstract class DatabaseComponentImpl<T> implements DatabaseComponent,
|
||||
DatabaseCleaner.Callback {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(DatabaseComponentImpl.class.getName());
|
||||
|
||||
protected final Database<Txn> db;
|
||||
protected final Database<T> db;
|
||||
protected final DatabaseCleaner cleaner;
|
||||
|
||||
private final List<DatabaseListener> listeners =
|
||||
@@ -38,7 +38,7 @@ DatabaseCleaner.Callback {
|
||||
private long timeOfLastCheck = 0L; // Locking: spaceLock
|
||||
private volatile boolean writesAllowed = true;
|
||||
|
||||
DatabaseComponentImpl(Database<Txn> db, DatabaseCleaner cleaner) {
|
||||
DatabaseComponentImpl(Database<T> db, DatabaseCleaner cleaner) {
|
||||
this.db = db;
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ DatabaseCleaner.Callback {
|
||||
* <p>
|
||||
* Locking: messages write.
|
||||
*/
|
||||
private int calculateSendability(Txn txn, Message m) throws DbException {
|
||||
private int calculateSendability(T txn, Message m) throws DbException {
|
||||
int sendability = 0;
|
||||
// One point for a good rating
|
||||
if(db.getRating(txn, m.getAuthor()) == Rating.GOOD) sendability++;
|
||||
@@ -121,7 +121,7 @@ DatabaseCleaner.Callback {
|
||||
* Locking: contacts read.
|
||||
*/
|
||||
protected boolean containsContact(ContactId c) throws DbException {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
boolean contains = db.containsContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
@@ -137,7 +137,7 @@ DatabaseCleaner.Callback {
|
||||
* <p>
|
||||
* Locking: contacts read, messages write, messageStatuses write.
|
||||
*/
|
||||
protected void removeMessage(Txn txn, MessageId id) throws DbException {
|
||||
protected void removeMessage(T txn, MessageId id) throws DbException {
|
||||
Integer sendability = db.getSendability(txn, id);
|
||||
assert sendability != null;
|
||||
// If the message is sendable, deleting it may affect its ancestors'
|
||||
@@ -176,7 +176,7 @@ DatabaseCleaner.Callback {
|
||||
* <p>
|
||||
* Locking: contacts read, messages write, messageStatuses write.
|
||||
*/
|
||||
protected boolean storeGroupMessage(Txn txn, Message m, ContactId sender)
|
||||
protected boolean storeGroupMessage(T txn, Message m, ContactId sender)
|
||||
throws DbException {
|
||||
if(m.getGroup() == null) throw new IllegalArgumentException();
|
||||
boolean stored = db.addGroupMessage(txn, m);
|
||||
@@ -204,7 +204,7 @@ DatabaseCleaner.Callback {
|
||||
* Attempts to store the given messages, received from the given contact,
|
||||
* and returns true if any were stored.
|
||||
*/
|
||||
protected boolean storeMessages(Txn txn, ContactId c,
|
||||
protected boolean storeMessages(T txn, ContactId c,
|
||||
Collection<Message> messages) throws DbException {
|
||||
boolean anyStored = false;
|
||||
for(Message m : messages) {
|
||||
@@ -226,7 +226,7 @@ DatabaseCleaner.Callback {
|
||||
* <p>
|
||||
* Locking: contacts read, messages write, messageStatuses write.
|
||||
*/
|
||||
protected boolean storePrivateMessage(Txn txn, Message m, ContactId c,
|
||||
protected boolean storePrivateMessage(T txn, Message m, ContactId c,
|
||||
boolean incoming) throws DbException {
|
||||
if(m.getGroup() != null) throw new IllegalArgumentException();
|
||||
if(m.getAuthor() != null) throw new IllegalArgumentException();
|
||||
@@ -250,7 +250,7 @@ DatabaseCleaner.Callback {
|
||||
* @param increment True if the message's sendability has changed from 0 to
|
||||
* greater than 0, or false if it has changed from greater than 0 to 0.
|
||||
*/
|
||||
private int updateAncestorSendability(Txn txn, MessageId m,
|
||||
private int updateAncestorSendability(T txn, MessageId m,
|
||||
boolean increment) throws DbException {
|
||||
int affected = 0;
|
||||
boolean changed = true;
|
||||
@@ -285,7 +285,7 @@ DatabaseCleaner.Callback {
|
||||
* @param increment True if the user's rating for the author has changed
|
||||
* from not good to good, or false if it has changed from good to not good.
|
||||
*/
|
||||
protected void updateAuthorSendability(Txn txn, AuthorId a,
|
||||
protected void updateAuthorSendability(T txn, AuthorId a,
|
||||
boolean increment) throws DbException {
|
||||
int direct = 0, indirect = 0;
|
||||
for(MessageId id : db.getMessagesByAuthor(txn, a)) {
|
||||
|
||||
@@ -38,9 +38,11 @@ import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* An implementation of DatabaseComponent using reentrant read-write locks.
|
||||
* This implementation can allow writers to starve.
|
||||
* Depending on the JVM's read-write lock implementation, this implementation
|
||||
* may allow writers to starve. LockFairnessTest can be used to test whether
|
||||
* this implementation is safe on a given JVM.
|
||||
*/
|
||||
class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
class ReadWriteLockDatabaseComponent<T> extends DatabaseComponentImpl<T> {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ReadWriteLockDatabaseComponent.class.getName());
|
||||
@@ -66,7 +68,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
new ReentrantReadWriteLock(true);
|
||||
|
||||
@Inject
|
||||
ReadWriteLockDatabaseComponent(Database<Txn> db, DatabaseCleaner cleaner) {
|
||||
ReadWriteLockDatabaseComponent(Database<T> db, DatabaseCleaner cleaner) {
|
||||
super(db, cleaner);
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
for(MessageId m : db.getOldMessages(txn, size)) {
|
||||
removeMessage(txn, m);
|
||||
@@ -111,7 +113,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
c = db.addContact(txn, transports, secret);
|
||||
db.commitTransaction(txn);
|
||||
@@ -143,7 +145,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
// Don't store the message if the user has
|
||||
// unsubscribed from the group or the message
|
||||
@@ -184,7 +186,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
added = storePrivateMessage(txn, m, c, false);
|
||||
db.commitTransaction(txn);
|
||||
@@ -215,7 +217,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
lost = db.getLostBatches(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
@@ -240,7 +242,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Removing lost batch");
|
||||
@@ -269,7 +271,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<BatchId> acks = db.getBatchesToAck(txn, c);
|
||||
Collection<BatchId> sent = new ArrayList<BatchId>();
|
||||
@@ -307,7 +309,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
sent = new ArrayList<MessageId>();
|
||||
int capacity = b.getCapacity();
|
||||
@@ -338,7 +340,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
BatchId id = b.finish();
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.addOutstandingBatch(txn, c, id, sent);
|
||||
db.commitTransaction(txn);
|
||||
@@ -369,7 +371,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try{
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
sent = new ArrayList<MessageId>();
|
||||
considered = new ArrayList<MessageId>();
|
||||
@@ -406,7 +408,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
BatchId id = b.finish();
|
||||
messageStatusLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.addOutstandingBatch(txn, c, id, sent);
|
||||
db.commitTransaction(txn);
|
||||
@@ -435,7 +437,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
messageStatusLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<MessageId> sendable =
|
||||
db.getSendableMessages(txn, c, Integer.MAX_VALUE);
|
||||
@@ -474,7 +476,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<Group, Long> subs = db.getVisibleSubscriptions(txn, c);
|
||||
s.writeSubscriptions(subs, System.currentTimeMillis());
|
||||
@@ -503,7 +505,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, Map<String, String>> transports =
|
||||
db.getTransports(txn);
|
||||
@@ -533,7 +535,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
windowLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
ConnectionWindow w =
|
||||
db.getConnectionWindow(txn, c, transportId);
|
||||
@@ -554,7 +556,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
public Collection<ContactId> getContacts() throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<ContactId> contacts = db.getContacts(txn);
|
||||
db.commitTransaction(txn);
|
||||
@@ -571,7 +573,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
public Rating getRating(AuthorId a) throws DbException {
|
||||
ratingLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Rating r = db.getRating(txn, a);
|
||||
db.commitTransaction(txn);
|
||||
@@ -589,7 +591,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
byte[] secret = db.getSharedSecret(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
@@ -606,7 +608,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
public Collection<Group> getSubscriptions() throws DbException {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<Group> subs = db.getSubscriptions(txn);
|
||||
db.commitTransaction(txn);
|
||||
@@ -624,7 +626,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, String> config = db.getTransportConfig(txn, name);
|
||||
db.commitTransaction(txn);
|
||||
@@ -641,7 +643,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
public Map<String, Map<String, String>> getTransports() throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, Map<String, String>> transports =
|
||||
db.getTransports(txn);
|
||||
@@ -663,7 +665,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
transportLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, Map<String, String>> transports =
|
||||
db.getTransports(txn, c);
|
||||
@@ -686,7 +688,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<ContactId> visible = db.getVisibility(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
@@ -713,7 +715,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
boolean has = db.hasSendableMessages(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
@@ -747,7 +749,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
Collection<BatchId> acks = a.getBatchIds();
|
||||
for(BatchId ack : acks) {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.removeAckedBatch(txn, c, ack);
|
||||
db.commitTransaction(txn);
|
||||
@@ -781,7 +783,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
anyAdded = storeMessages(txn, c, b.getMessages());
|
||||
db.addBatchToAck(txn, c, b.getId());
|
||||
@@ -819,7 +821,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
Collection<MessageId> offered = o.getMessageIds();
|
||||
BitSet request = new BitSet(offered.size());
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Iterator<MessageId> it = offered.iterator();
|
||||
for(int i = 0; it.hasNext(); i++) {
|
||||
@@ -857,7 +859,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<Group, Long> subs = s.getSubscriptions();
|
||||
db.setSubscriptions(txn, c, subs, s.getTimestamp());
|
||||
@@ -884,7 +886,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, Map<String, String>> transports =
|
||||
t.getTransports();
|
||||
@@ -917,7 +919,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.removeContact(txn, c);
|
||||
db.commitTransaction(txn);
|
||||
@@ -951,7 +953,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
if(!containsContact(c)) throw new NoSuchContactException();
|
||||
windowLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.setConnectionWindow(txn, c, transportId, w);
|
||||
db.commitTransaction(txn);
|
||||
@@ -971,7 +973,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
ratingLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Rating old = db.setRating(txn, a, r);
|
||||
// Update the sendability of the author's messages
|
||||
@@ -997,7 +999,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
boolean changed = false;
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, String> old = db.getTransportConfig(txn, name);
|
||||
if(!config.equals(old)) {
|
||||
@@ -1021,7 +1023,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
boolean changed = false;
|
||||
transportLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Map<String, String> old = db.getTransports(txn).get(name);
|
||||
if(!properties.equals(old)) {
|
||||
@@ -1046,7 +1048,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
// Remove any ex-contacts from the set
|
||||
Collection<ContactId> present =
|
||||
@@ -1073,7 +1075,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
boolean added = false;
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(db.containsSubscription(txn, g.getId())) {
|
||||
db.addSubscription(txn, g);
|
||||
@@ -1102,7 +1104,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(db.containsSubscription(txn, g)) {
|
||||
db.removeSubscription(txn, g);
|
||||
|
||||
Reference in New Issue
Block a user