I have to do an assignment where I have to implement a background thread logger for a web service, for the logger we got some skeleton code where we have a run method and a method that returns a future object. For logging of activities we have to implement write ahead logging, I managed to start a new thread for the logger and I send it the command to log something when I execute an insert/update command in the web service (the web service implements a key to values map), but I can`t manage to make the main thread wait for the logging thread to finish logging. Does anybody have any suggestions? Maybe I am doing something wrong?
public class IndexImpl implements Index<KeyImpl,ValueListImpl>
{
private Thread log_thread;
private MyLogger log;
/*
* in out pair, the long refers to the initial memory address that our data
* has been saved too, and the integer refers to the length of the data in the file
*/
private HashMap<KeyImpl,Pair<Long,Integer>> m;
private long endAddr;
public IndexImpl()
{
valSer = new ValueSerializerImpl();
endAddr = 0;
m = new HashMap<KeyImpl,Pair<Long,Integer>>();
this.log= new MyLogger();
this.log_thread= new Thread(log);
log_thread.start();
}
public void insert(KeyImpl k, ValueListImpl v) throws KeyAlreadyPresentException, IOException {
locker.WriteLock(k);
try {
if (m.containsKey(k)) {
throw new KeyAlreadyPresentException(k);
}
else {
//LOGGING
Object[] array = new Object[3]; // Key, Old Value List, New Value List
array[0]= k.toString(); //Key
array[1]= null; // Old value list
array[2]= v; // New value list
LogRecord l = new LogRecord(MyKeyValueBaseLog.class, "insert", array);
FutureLog<LogRecord> future = (FutureLog<LogRecord>) log.logRequest(l);
System.out.println("Inserting a new key " + k.getKey());
future.get();
long tempEndAddr;
byte[] temp = valSer.toByteArray(v);
//we are using the ReentrantReadWriteLock implementation found in java
write.lock();
try{
tempEndAddr = endAddr;
endAddr += temp.length;
}
finally{
write.unlock();
}
store.write(tempEndAddr, temp);
m.put(k, new Pair<Long, Integer>(tempEndAddr,temp.length));
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
locker.WriteUnlock(k);
}
}
And the code for the logger is :
public class MyLogger implements Logger {
private ArrayList<LogRecord> log = new ArrayList<LogRecord>(100);
public MyLogger()
{
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("This is the logger thread! " + Thread.currentThread());
}
@Override
public Future<?> logRequest(LogRecord record) {
// TODO Auto-generated method stub
this.log.add(record);
System.out.println("Record added to log! operation: " + record.getMethodName() );
FutureLog<LogRecord> future = new FutureLog();
return future;
}
}
Your logger thread is started and will exit immediately
Instead, you need to loop in this method, writing log records as they come in. I would perhaps suggest reading from a BlockingQueue, and the method logRequest() should add log records to this queue. That way your
run()method will just wait on the queue (using the take() method provided by the queue) and write out each record as it takes it off the queue.You’ll need to be able to stop this, and perhaps interrupting the thread is a solution here.
All of the above is simply one implementation choice. The fundamental problem you have is that your thread starts/stops almost instantaneously.