mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Factored out the database cleaner.
This commit is contained in:
32
components/net/sf/briar/db/DatabaseCleaner.java
Normal file
32
components/net/sf/briar/db/DatabaseCleaner.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.sf.briar.db;
|
||||
|
||||
import net.sf.briar.api.db.DbException;
|
||||
|
||||
interface DatabaseCleaner {
|
||||
|
||||
/**
|
||||
* Starts a new thread to monitor the amount of free storage space
|
||||
* available to the database and expire old messages as necessary.
|
||||
*/
|
||||
void startCleaning();
|
||||
|
||||
/** Tells the cleaner thread to exit and returns when it has done so. */
|
||||
void stopCleaning();
|
||||
|
||||
interface Callback {
|
||||
|
||||
/**
|
||||
* Checks how much free storage space is available to the database, and if
|
||||
* necessary expires old messages until the free space is at least
|
||||
* MIN_FREE_SPACE. While the free space is less than CRITICAL_FREE_SPACE,
|
||||
* operations that attempt to store messages in the database will block.
|
||||
*/
|
||||
void checkFreeSpaceAndClean() throws DbException;
|
||||
|
||||
/**
|
||||
* Called by the cleaner; returns true iff the amount of free storage space
|
||||
* available to the database should be checked.
|
||||
*/
|
||||
boolean shouldCheckFreeSpace();
|
||||
}
|
||||
}
|
||||
54
components/net/sf/briar/db/DatabaseCleanerImpl.java
Normal file
54
components/net/sf/briar/db/DatabaseCleanerImpl.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package net.sf.briar.db;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class DatabaseCleanerImpl implements DatabaseCleaner, Runnable {
|
||||
|
||||
private final Callback db;
|
||||
private final int msBetweenSweeps;
|
||||
private final AtomicBoolean stopped = new AtomicBoolean(false);
|
||||
private final Thread cleanerThread = new Thread(this);
|
||||
|
||||
@Inject
|
||||
DatabaseCleanerImpl(Callback db, int msBetweenSweeps) {
|
||||
this.db = db;
|
||||
this.msBetweenSweeps = msBetweenSweeps;
|
||||
}
|
||||
|
||||
public void startCleaning() {
|
||||
cleanerThread.start();
|
||||
}
|
||||
|
||||
public void stopCleaning() {
|
||||
stopped.set(true);
|
||||
// If the cleaner thread is waiting, wake it up
|
||||
synchronized(stopped) {
|
||||
stopped.notifyAll();
|
||||
}
|
||||
try {
|
||||
cleanerThread.join();
|
||||
} catch(InterruptedException ignored) {}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
while(!stopped.get()) {
|
||||
if(db.shouldCheckFreeSpace()) {
|
||||
db.checkFreeSpaceAndClean();
|
||||
} else {
|
||||
synchronized(stopped) {
|
||||
try {
|
||||
stopped.wait(msBetweenSweeps);
|
||||
} catch(InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Throwable t) {
|
||||
// FIXME: Work out what to do here
|
||||
t.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,14 @@ import com.google.inject.Provider;
|
||||
* Abstract superclass containing code shared by ReadWriteLockDatabaseComponent
|
||||
* and SynchronizedDatabaseComponent.
|
||||
*/
|
||||
abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||
abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent,
|
||||
DatabaseCleaner.Callback {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(DatabaseComponentImpl.class.getName());
|
||||
|
||||
protected final Database<Txn> db;
|
||||
protected final DatabaseCleaner cleaner;
|
||||
protected final Provider<Batch> batchProvider;
|
||||
|
||||
private final Object spaceLock = new Object();
|
||||
@@ -33,10 +35,16 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||
private long timeOfLastCheck = 0L; // Locking: spaceLock
|
||||
private volatile boolean writesAllowed = true;
|
||||
|
||||
DatabaseComponentImpl(Database<Txn> db, Provider<Batch> batchProvider) {
|
||||
DatabaseComponentImpl(Database<Txn> db, DatabaseCleaner cleaner,
|
||||
Provider<Batch> batchProvider) {
|
||||
this.db = db;
|
||||
this.cleaner = cleaner;
|
||||
this.batchProvider = batchProvider;
|
||||
startCleaner();
|
||||
}
|
||||
|
||||
public void open(boolean resume) throws DbException {
|
||||
db.open(resume);
|
||||
cleaner.startCleaning();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,13 +71,7 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||
return sendability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks how much free storage space is available to the database, and if
|
||||
* necessary expires old messages until the free space is at least
|
||||
* MIN_FREE_SPACE. While the free space is less than CRITICAL_FREE_SPACE,
|
||||
* operations that attempt to store messages in the database will block.
|
||||
*/
|
||||
private void checkFreeSpaceAndClean() throws DbException {
|
||||
public void checkFreeSpaceAndClean() throws DbException {
|
||||
long freeSpace = db.getFreeSpace();
|
||||
while(freeSpace < MIN_FREE_SPACE) {
|
||||
// If disk space is critical, disable the storage of new messages
|
||||
@@ -123,11 +125,7 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||
db.removeMessage(txn, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the amount of free storage space available to the
|
||||
* database should be checked.
|
||||
*/
|
||||
private boolean shouldCheckFreeSpace() {
|
||||
public boolean shouldCheckFreeSpace() {
|
||||
synchronized(spaceLock) {
|
||||
long now = System.currentTimeMillis();
|
||||
if(bytesStoredSinceLastCheck > MAX_BYTES_BETWEEN_SPACE_CHECKS) {
|
||||
@@ -149,35 +147,6 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new thread to monitor the amount of free storage space
|
||||
* available to the database and expire old messages as necessary.
|
||||
* <p>
|
||||
* FIXME: The thread implementation should be factored out.
|
||||
*/
|
||||
private void startCleaner() {
|
||||
Runnable cleaner = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
while(true) {
|
||||
if(shouldCheckFreeSpace()) {
|
||||
checkFreeSpaceAndClean();
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(CLEANER_SLEEP_MS);
|
||||
} catch(InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
} catch(Throwable t) {
|
||||
// FIXME: Work out what to do here
|
||||
t.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
new Thread(cleaner).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given message is already in the database, marks it as seen by the
|
||||
* sender and returns false. Otherwise stores the message, updates the
|
||||
|
||||
@@ -47,12 +47,13 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
new ReentrantReadWriteLock(true);
|
||||
|
||||
@Inject
|
||||
ReadWriteLockDatabaseComponent(Database<Txn> db,
|
||||
ReadWriteLockDatabaseComponent(Database<Txn> db, DatabaseCleaner cleaner,
|
||||
Provider<Batch> batchProvider) {
|
||||
super(db, batchProvider);
|
||||
super(db, cleaner, batchProvider);
|
||||
}
|
||||
|
||||
public void close() throws DbException {
|
||||
cleaner.stopCleaning();
|
||||
contactLock.writeLock().lock();
|
||||
try {
|
||||
messageLock.writeLock().lock();
|
||||
|
||||
@@ -41,12 +41,13 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
private final Object subscriptionLock = new Object();
|
||||
|
||||
@Inject
|
||||
SynchronizedDatabaseComponent(Database<Txn> db,
|
||||
SynchronizedDatabaseComponent(Database<Txn> db, DatabaseCleaner cleaner,
|
||||
Provider<Batch> batchProvider) {
|
||||
super(db, batchProvider);
|
||||
super(db, cleaner, batchProvider);
|
||||
}
|
||||
|
||||
public void close() throws DbException {
|
||||
cleaner.stopCleaning();
|
||||
synchronized(contactLock) {
|
||||
synchronized(messageLock) {
|
||||
synchronized(messageStatusLock) {
|
||||
|
||||
Reference in New Issue
Block a user