I would like to know different opinions on Synchronization of Create/Update method:
1. Synchronize Entire method?
2. ReadWriteLock on recordNumbers -
a. If the option is create add the recordNumber and location(append at the end) to the collection and release the lock.
b. Synchronize on raf and write to file?
My concern with option 2 is - what if there is a read/write between 2a and 2b.
I went for the first option: synchronize all methods (so not only create and update). of course your data class should certainly be a singleton, otherwise it will not have any effect.
The drawback of this approach is that your program is not that concurrent/performant as it could be. But your code is very simple, clear and can easily be understood by a junior programmer.
The second option is similar to how it is described in the Andrew Monkhouse book. And i think the main concern there is what if 2 client will create a new record.
client1: determine offset, offset = database.length
client2: determine offset, offset = database.length
client2: write record at end of file
client1: write record at end of file (and so overwrite the record written by client2)
a read or an update or a delete in between (offset determination and the actual write) would have no effect in my opinion, because the records are fixed size, so updating or deleting a record will result in same size.
I don't have any idea about how to solve this item and i looked to sources of Andrew's book and there can just happen the same i guess.
1. Data-class has one ReentrantLock, which controls access to lock-hashmap containing locked record numbers
-> Methods are NOT synchronized (you should do this in any case - no matter what's your approach)
2. Every client should instantiate Data-class
3. Every client get's own access to file - that is, RandomAccessFile is opened every time
4. I'm using WRITE_LOCK = -1, to inform, that writing is forbidden while using find method
-> Gives real concurrent access to file
-> Already tried with Cache-implementation - too compilcated -> changed whole back end.
-> UB 1.3.3 does not define lock cookie -> RMI Factory Design pattern is a must, since RMI does not guarantee single thread access to server from client.
Jari Timonen wrote:
UB 1.3.3 does not define lock cookie -> RMI Factory Design pattern is a must, since RMI does not guarantee single thread access to server from client.
UB 1.3.1 also defines no lockCookie, but i didn't use the RMI factory design pattern. so it is not a must
Jari Timonen wrote:
UB 1.3.3 does not define lock cookie -> RMI Factory Design pattern is a must, since RMI does not guarantee single thread access to server from client.
UB 1.3.1 also defines no lockCookie, but i didn't use the RMI factory design pattern. so it is not a must
Ok. Maybe i'm just too accurate ;) But... there is then possibility, that thread that locks record and after that reads it, is different.
Vijay Sai wrote:Thanks Roel for your detailed explanation. I think Synchronizing entire method may impact some performance but that seem to be the simpler approach.
I wonder how many people used the 2nd option!? and how they implemented it? hope someone answers it, I'm curious to know.
Thank you,
Vijay
Hi,
I like your idea about locking whole methods, did you used it in your assignment and did you passed?
I thought of exploring the 2nd option to learn more but didn't get a chance to implement it. I'll be restarting it soon. For the first option, you can implement it as Roel mentioned above.
Jari Timonen wrote:
UB 1.3.3 does not define lock cookie -> RMI Factory Design pattern is a must, since RMI does not guarantee single thread access to server from client.
UB 1.3.1 also defines no lockCookie, but i didn't use the RMI factory design pattern. so it is not a must
Ok. Maybe i'm just too accurate ;) But... there is then possibility, that thread that locks record and after that reads it, is different.
There are several ways that you can ensure that the client who locked the record is the client who is modifying the record without using a factory, although I personally think the factory method is the most elegant.
The lock method you expose via RMI does not use the same signature as the lock method defined in the Sun interface. Given that, you could easily justify modifying your RMI methods even further - say by creating your own lock cookie or some other "id" field. When the client calls the remote method with that ID field set, you could use it to set the name of the thread that is currently running for that particular client which can then be used within the Data class' methods.
Or there is the option that I believe is against the intent of the assignment (but you will not be marked down for doing this) - only expose business methods to the client. If you only expose a book() method, and that book method internally calls lock(), update(), unlock() then you will be assured that the same thread is calling all three methods. Makes a mockery of having cookies (for those who have cookies).
Note that although I have said that I prefer the factory solution, and although I believe that only exposing business methods is going against the intent of the assignment, I am also explicitly stating that this is pure hubris on my part: the reality is that this assignment (as with most assignments you will get in real life) was written by someone else, and any attempt to state that "this is what they intended" based on just a reading of the provided document is bad mind reading at best. In a real life situation you would be better off going to the author of the document and saying "here are 'x' number of possible ways of handling this problem - which do you prefer. You might then find that they never considered the problem you've found, and/or that they think that solution 'y' is better than anything that they had previously thought of. Meh.
Jari Timonen wrote:Thanks Andrew. I already hide my lock/unlock methods from RMI. Exposed only business methods. I'm using thread id as locking cookie inside Data-class
Sounds too simple to me, but maybe I am worried for nothing so to be sure you don't make mistake in the rmi part.
If you have an interface with a lockCookie you should use that one to make sure the right client locks/updates/unlocks the record. If you don't have a lockCookie in your interface, you should be aware that RMI doesnot guarantee that consecutive requests from 1 client are handled by the same thread.
Jari Timonen wrote:Thanks Andrew. I already hide my lock/unlock methods from RMI. Exposed only business methods. I'm using thread id as locking cookie inside Data-class
Sounds too simple to me, but maybe I am worried for nothing so to be sure you don't make mistake in the rmi part.
If you have an interface with a lockCookie you should use that one to make sure the right client locks/updates/unlocks the record. If you don't have a lockCookie in your interface, you should be aware that RMI doesnot guarantee that consecutive requests from 1 client are handled by the same thread.
Kind regards,
Roel
I'm aware of those. There's no locking cookie in my interface. As I said before, factory design + thin client is a must OR andews "set thread name" strategy.
Vijay Sai wrote:
1.get writelock
2. In the try /catch block - synchronize(RAF) and write to the db.
3. unlock in the finally block
don't know what you mean with "3. unlock"? If you mean a call to the unlock-method from within the update/delete method, I don't think that's a good idea. These methods should just do what they are supposed to do, and that's updating/deleting, not locking/unlocking the record. This should be seperate calls.
Without the use of a lockCookie to update a record it would look like this
in the update-method you would have something like:
So the seek and the write should always be 1 atomic operation, otherwise you could corrupt your data file.
Could you edit your previous post and put your code blocks in code-tags, it keeps the identation intact and so makes your code snippets a lot more readible