• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

NX: Client side lock vs Server side lock

 
Eric Kim
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I am fine tuning my locking implementation and found this different issue:
Choice 1: Client side locking
That is I expose lock()/unlock() to client besides create(), update(), delete() and find(). So when clients wants to update, it must make call like this:
lock()
update()
unlock()
While this works well if client code always work this way and there is no network interruption or client crash. If somehow client crashes/terminates before it has chance to execute unlock(), record will remain locked until server is restarted. I tried to use timeout on wait() or control the lock duration (If lock is hold for more than 5 seconds, automatically expire it), but the code get too complex, and it is not smart enough to detect whether it is a long operation between lock() and unlock() cycle, or just client crash, so a long running lock is also forced to released. This is not good.
Choice 2. Server side locking.
In this case I don't expose lock()/unlock() to client, client can only access create()/update()/delete()/find() method, and inside update() for instance, it will lock record first, then does its updates, and then unlock it.
This will never cause deadlock when client crashes because to client, each database operation is atomic, if a record is locked, it will always be unlocked.
However, I find this also have serious flaw. In one of the test case I created, it can not do what it is supposed to do:

If we wrap this in a loop for 1000 times and put this loop into a thread run() function, then start 20 threads to run it, you would expect after these 20 threads finishes, field 6 will be 20000 larger than initial value.
However, with choice 2 the result is not. Because of the way the locking is handled, two threads can get the same value, then each try to update this field with its own copy, so the result could be 9000 or whatever, and it is undeterministic.
I find there is no way to get test case work with server side locking.
Any comments are appreciated.
 
Eric Kim
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
According to this port,
http://www.coderanch.com/t/185337/java-developer-SCJD/certification/Lock
client crash detection is not a requirement, so perhaps I can just document it and not to think about it for now.
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Eric,
I think you can successfully argue in your design choices document that lock recovery when a client dies is beyond the scope of the assignment.
Originally posted by Eric Kim:

I find there is no way to get test case work with server side locking.

I think the problem may be your implementation of server side locking rather than an inherent flaw in server side locking.
I think your seeing a manifestation of the stale record problem in your testing.
For example, when the client books a record it is essentially doing a read followed by an update. So on the client side it looks like this:

When these requests reach the server side they effectively get translated into:

So notice that there is a period of time (in bold) where the recNo is not locked. The contents of the record can be changed during this period.
Let's look at a possible scenario:
Thread 1 tries to book recNo=30
Thread 1 obtains lock on recNo=30
Thread 1 reads recNo=30 and finds that owner is 12
Thread 1 releases lock on recNo=30
Thread 2 tries to book recNo=30
Thread 2 obtains lock on recNo=30
Thread 2 reads recNo=30 and finds that owner is 12
Thread 2 releases lock on recNo=30
Thread 2 obtains lock on recNo=30
Thread 2 updates recNo=30 setting owner to previously read value + 1 = 13
Thread 2 releases lock on recNo=30
Thread 1 obtains lock on recNo=30
Thread 1 updates recNo=30 setting owner to previously read value = 1 = 13
Thread 1 releases lock on recNo=30
So we would have expected that after thread 1 and 2 finished executing we would have seen the owner go from 12 to 14. Instead we have seen owner go from 12 to 13. Effectively thread 2's update was lost because thread 1 updated a stale (out-of-date) record.
The moral of this story is that if you don't expose lock and unlock to the client, but you do expose read and update, then you can't expect him to be able to do the following:
lock, read, update, unlock
which is what he needs to do in order to correctly do a book operation.
So if you're going to withhold lock and unlock from the client then you shouldn't expose read and update either because they can't be used correctly because you are not providing the client anyway to treat the read and update sequence atomically. However, if you only provide a server side business method like book to the client then you can implement book as follows:

So I think the book method presented above would perform correctly in your testing. The book method implements server side locking, the client is not aware of locking in this case.
 
Eric Kim
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi George,
I totally agree with you, if I only expose book()/find()/getColumnName()/GetRecordCount() methods to client, and implement lock in both book() and find() on server side, then it can handle the test case quite nicely and there is no chance to create deadlock or stale data even if client crashes.
My understanding is the UI just need book() (Essentially a read and then update) and find() business methods, UI does not need to create record on the server side, am I correct?
Another issue is in the instruction it mentions that when run UI as a standalone app, no locking is allowed. Obviously no locking is required in this case, but in the Data class it will still check lock cookie as the interface is something like this:

How should I address this issue?
Thanks,
Eric
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Eric,
Originally posted by Eric Kim:
My understanding is the UI just need book() (Essentially a read and then update) and find() business methods, UI does not need to create record on the server side, am I correct?

Yes, there's no need to make create avaliable outside the Data class.

Another issue is in the instruction it mentions that when run UI as a standalone app, no locking is allowed. Obviously no locking is required in this case, but in the Data class it will still check lock cookie as the interface is something like this:

How should I address this issue?


Are you sure about no locking being allowed when you run the UI as a standalone application? If so this is a new requirement. I looked in my assignment instructions (B&S Contractors v2.2.3):
Non-Networked Mode
The program must be able to work in a non-networked mode. In this mode, the database and GUI must run in the same VM and must perform no networking, must not use loopback networking, and must not involve the serialization of any objects when communicating between the GUI and database elements.
The operating mode is selected using the single command line argument that is permitted. Architecturally, this mode must use the database and GUI from the networked form, but must not use the network server code at all.

and could find no mention of this requirement.
Since I didn't have this requirement I allowed locking to take place in standalone mode (where it wasn't needed) as well as the networked modes. I haven't thought much about this, but it strikes me that you would have to approach this in the same way you went about supporting local database access and remote database access. That is, a common interface that can be called by the GUI client implemented by two different classes (one supporting local access without locking, and the other supporting remote access with locking).
Given your lock and unlock signatures it's clear that locking would have to be implemented in the Data class. Also, the lock and unlock methods should honor the contract specified by the method comments specified in the Sun interface. Maybe you could have another Data class, perhaps DataLite that would implement the same methods (except for the lock, unlock, isLocked) but without the locking. Before you go down this path I would make sure that you really have the requirement not to use locking when running in standalone mode.
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 12007
215
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Eric,
Originally posted by Eric Kim (in response to George):
I totally agree with you, if I only expose book()/find()/getColumnName()/GetRecordCount() methods to client, and implement lock in both book() and find() on server side, then it can handle the test case quite nicely and there is no chance to create deadlock or stale data even if client crashes.

Why are you implementing locking in the find method? You may be able to remove that, which will give you better performance.
Since you appear to be unsure whether you are going to expose the lock method to the client or not, I will point you to the thread "Should lock methods be callable by the client?" - this is a very long thread (4 pages), but it covers most of the reasons for and against exposing lock methods to the client. It may help you firm up your decision about which way to go .
Regards, Andrew
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Eric,
I agree with Andrew's point about not using locking in the find method. I guess it escaped my notice the first time or I would have mentioned it.
Also, heartily agree that you should check out the infamous "should lock methods be callable by the client" thread that Andrew recommended.
I'm sure the point is made in that thread somewhere, but one consequence of your decision is the effect it will have on your client's implementation of the booking operation. If you allow the client to call the lock methods then the client can implement what I've called pessimistic booking, wherein you don't ask the user for a customer Id until you have successfully acquired a lock on the record. If you don't allow the client to call the lock methods then the client will have to implement what I've called optimistic booking, wherein you ask the user for a customer id before you have successfully acquired a lock on the record. Personally I'm a pessimist, but many others around here seem to be optimists.
 
Javini Javono
Ranch Hand
Posts: 286
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi George,
Thanks for your posts which are always detailed and informative.
I take it that the major difference between the o-lock and the p-lock, is that
1. In the o-lock, you might have to come back to your client and say, "sorry,
but that room is no longer available."
2. In the p-lock, you know in advance that it is available since you hold the
lock until the client either clicks "book" or "cancel."
Thanks,
Javini Javono
 
George Marinkovich
Ranch Hand
Posts: 619
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Javini,
Originally posted by Javini Javono:
I take it that the major difference between the o-lock and the p-lock, is that
1. In the o-lock, you might have to come back to your client and say, "sorry,
but that room is no longer available."
2. In the p-lock, you know in advance that it is available since you hold the
lock until the client either clicks "book" or "cancel."

Yes, that's it in a nutshell.
Personally, I can't justify asking the user to do work and then have to come back to him under some circumstance and say "I guess you didn't need to do that, sorry for leading you on, mate!" Because if the user said "Well couldn't you have known that it wouldn't work before you asked me to type in the customer ID?" I wouldn't know what to say...
I try to keep my users happy (or at least try not to needlessly irritate them). I only irritate them when it's absolutely necessary... or it's a really slow day...
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic