class KWICDB implements KWICDBInterface private DBWriterClient writerClient private DBReaderClient readerClient private KWICDatabase kwicdb public String [] query(String keywords[]) readerClient.enter() String [] entries = kwicdb.get(keywords) readerClient.exit() return entries public void write(String description) writerClient.enter() kwicdb.put(description) writerClient.exit()
abstract class DBClientTemplate protected DatabaseAccess dba abstract boolean databaseSafe() abstract void databaseWait() abstract void databaseEnter() abstract void databaseExit() DBClientTemplate(DatabaseAccess dba) this.dba = dba void enter() dba.mutex.lock() if (!databaseSafe()) databaseWait() databaseEnter() void exit() try dba.mutex.lock() catch (InterruptedException ie) Thread.currentThread().interrupt() databaseExit()
See the complete code.
class DBClient extends DBClientTemplate DBClient(DatabaseAccess dba) super(dba) boolean databaseSafe() return true void databaseWait() assert false void databaseEnter() { } void databaseExit() dba.mutex.unlock() void exit() databaseExit()
class DatabaseAccess Mutex lock = new Mutex(Mutex.unlocked)
class DatabaseAccess Mutex mutex = new Mutex(Mutex.unlocked) HandoffConditionVariable emptyDatabase = new HandoffConditionVariable(mutex) noWriterInDB = new HandoffConditionVariable(mutex) boolean writerInDB = false int readersInDB = 0
class DBReaderClient extends DBClientTemplate boolean databaseSafe() return !dba.writerInDB void databaseWait() dba.emptyDatabase.pause() void databaseEnter() dba.readersInDB++ if dba.noWriterInDB.waiting() dba.noWriterInDB.resume() else dba.mutex.unlock() void databaseExit() dba.readersInDB-- if dba.emptyDatabase.waiting() dba.emptyDatabase.resume() else if dba.noWriterInDB.waiting() dba.noWriterInDB.resume() else dba.mutex.unlock()
See the complete code.
init()
and term()
init()
prevents database entry and exit.
term()
Allows database exit and prevents entry.
class DBInvalidWriterClient extends DBWriterClient void enter() throws InterruptedException throw new Error("The database is not accepting clients.") // exit() inherited from DBWriterClient.
DBInvalidReaderClient
is defined similarly.
init()
.
init()
classes that
explode on exit too.
init()
and term()
init()
changes them to valid clients.
term()
changes them back to invalid clients.
class KWICDB implements KWICDBInterface private DatabaseAccess dba = new DatabaseAccess() private DBClientTemplate invalidWriterClient = new DBInvalidWriterClient(dba) invalidReaderClient = new DBInvalidReaderClient(dba) readerClient = invalidReaderClient writerClient = invalidWriterClient public KWICDBInterface init() readerClient = new DBReaderClient(dba) writerClient = new DBWriterClient(dba) return this public void term() readerClient = invalidReaderClient writerClient = invalidWriterClient
See the complete code.
class QueueElement Mutex delay(Mutex.locked) boolean isReader boolean byPassed = false QueueElement next = null
class DatabaseAccess Mutex mutex = new Mutex(Mutex.unlocked) Queue waiters = new Queue() boolean writerInDB = false int readersInDB = 0
class DBReaderClient void entry() dba.mutex.lock() if !dba.waiters.empty() || dba.writerInDB QueueElement qe = dba.waiters.enq(true) dba.mutex.unlock() qe.delay.lock() dba.mutex.lock() if dba.waiters.head() != null if dba.waiters.head().isReader dba.waiters.deq().delay.unlock() readersInDB++ dba.mutex.unlock()
void exit() dba.mutex.lock() if --readersInDB == 0 if dba.waiters.head() != null if dba.waiters.head().isWriter dba.waiters.deq().delay.unlock() dba.mutex.unlock
class DBWriterClient void enter() dba.mutex.lock() if !dba.waiters.empty() || dba.writerInDB || dba.readersInDB > 0 QueueElement qe = dba.waiters.enq(false) dba.mutex.unlock() qe.delay.lock() dba.mutex.lock() writerInDB = true dba.mutex.unlock()
void exit() dba.mutex.lock() writerInDB = false if dba.waiters.head() != null dba.waiters.deq().delay.unlock() dba.mutex.unlock()
class DBWriterClient void enter() dba.mutex.lock() if !databaseSafe() QueueElement qe = dba.waiters.enq(true) dba.mutex.unlock() qe.delay.lock()dba.mutex.lock()writerInDB = true dba.mutex.unlock() void exit() dba.mutex.lock() writerInDB = false if dba.waiters.head() != null dba.waiters.deq().delay.unlock() else dba.mutex.unlock()
class QueueElement QueueElement next = null final KWICIndexEntryGroup entries QueueElement(KWICIndexEntryGroup entries) this.entries = entries interface QueueTraverser void forEach(KWICIndexEntryGroup entries) class Queue private QueueElement qhead = null boolean empty() { ... } void enq(QueueElement qe) { ... } QueueElement head() { ... } void traverse(QueueTraverser qt) QueueElement qe for (qe = qhead; qe != null; qe = qe.next) qt.forEach(qe.entries)
class KWICDB private KWICDatabase KWICDB = new KWICDatabase() private boolean entryOk = false public KWICDBInterface init() entryOk = true public String [] query(String keywords[]) if entryOk return KWICDB.get(keywords) else throw new Error() public void term() entryOk = false public void write(String description) if entryOk KWICDB.put(description) else throw new Error()
init()
and term()
.
This page last modified on 13 August 2002.