Reputation: 5646
I need some advice on following multi-threading scenario. I have a xml file which contain some configuration data for a web application. When a user access the website, base on the url accessed by the user, data from the XML file will be read to find out some properties attached to that user request. To improve the performance of reading from xml file, I have used Ehcache. I am caching the request and relevant configuration from xml in the cache.
So , now the problem I am facing is. If somebody start updating the xml file, I need to stop the reading from cache until writing is completed and once the xml file update operation is done, I want to clear the cache. Then cache will be rebuild again. For this second part, I am struggling on how to implement multi threading to achieve this. File update can be done in two ways, one is user directly editing the xml file using notepad++ or some other tool. other way is using the same web application.
Upvotes: 0
Views: 914
Reputation: 18148
You can refresh the cache using a pool of worker threads reading from a shared BlockingQueue; when the user finalizes their edit you'll send a message to the queue with information on the kv pairs that need to be updated.
public class RefreshRequest<K> {
public final K key;
public RefreshRequest(K key) { this.key = key; }
}
public final BlockingQueue<RefreshRequest<?>> requestQueue = new ArrayBlockingQueue<>(200);
public final int concurrency = 4;
public final ExecutorService executor = Executors.newFixedThreadPool(4);
for(int i = 0; i < concurrency; i++) {
executor.execute(new Runnable() {
public void run() {
try {
while(true) {
RefreshRequest<?> request = requestQueue.take();
// refresh key
}
} catch(InterruptedException e) {
return; // maybe log the exception as well
}
}
};
}
The workers will consume requests to refresh cache keys; you'll need to put
new requests on the queue from the code that finalizes a change to the xml file. To terminate the workers call executor.shutdownNow()
which will break out of the while(true)
loops with an InterruptedException
As for how to stop reading from the cache when somebody starts writing to the xml, you can do this with an "optimistic" read. Assign a version number to each xml file, and increment this version when you write to the file. When you start a read, store the file's version in a local variable. When the read finishes, compare the local version to the file's current version - if they match then return the read value, if they don't match then repeat the read including updating the local variable to the now-current file version. If need be you can have an "invalid" version (e.g. "valid" versions start at 0 and are incremented on each write, while an "invalid" version is negative-1) - if the reader reads that the file is "invalid" then it pauses for e.g. 5 seconds and then tries again. So one algorithm might be
public Object read(K key) {
while(true) {
int version = versionCache.get(key);
if(version == -1) Thread.sleep(5000);
else {
Object returnVal = cache.get(key);
if(version == versionCache.get(key))
return returnVal;
}
}
}
Upvotes: 1