File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes data locking; competing actions Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "data locking; competing actions" Watch "data locking; competing actions" New topic
Author

data locking; competing actions

Bridget Kennedy
Ranch Hand

Joined: Nov 30, 2004
Posts: 84
I'm having a little trouble with the spec in the area of record locking and thread management. I infer from the spec that clients queue up for access to specific records. I'm not sure what level of complexity is expected for managing the queue. For example, it seems to me that, operationally, you might run into trouble if thread A has a lock on record x for the purposes of performing a delete. Thread A finishes the delete, releases the record x lock, whereupon thread B siezes the lock to perform an update on record x. Is it a problem since record x is now a deleted record? At the time thread B initiated the update, it was a legitimate operation. While waiting, it became illegitimate. Is it illegitimate? Is it ok to usurp prior actions?

I tend to fall back on the notion that I probably won't get dinged for providing too much complexity. But I don't want to spend time unnecessarily on sophisticated solutions.

Thoughts and/or links to prior discussions of this issue will be most appreciated.
Jared Chapman
Ranch Hand

Joined: Feb 23, 2004
Posts: 81
Hi,

For example, it seems to me that, operationally, you might run into trouble if thread A has a lock on record x for the purposes of performing a delete. Thread A finishes the delete, releases the record x lock, whereupon thread B siezes the lock to perform an update on record x. Is it a problem since record x is now a deleted record? At the time thread B initiated the update, it was a legitimate operation. While waiting, it became illegitimate.


When thread B attempts to lock the record, it should throw a RecordNotFoundException. This is no different than the situation where a user does a search, goes to lunch, then comes back and attempts to book a particular record. There is no guarantee that the record is still there, because the data in the client's JTable is essentially outdated once it is returned. Even if they don't have to wait for the lock, it is possible that the record was deleted while they were on their lunch break, and their view hasn't been updated to reflect this change. How I handled this situation was to simply throw a RNFEx from Data, catch it on the client side, and display a dialog to the user that this record no longer exists, and that they should update their view to reflect recent changes.


B.S. University of Wisconsin<br />SCJP 1.4 (85%)<br />SCJD 1.4 (92%) B&S Contractors
Anton Golovin
Ranch Hand

Joined: Jul 02, 2004
Posts: 476
Bridget, the three possible solutions to thread management are located in this thread.


Anton Golovin (anton.golovin@gmail.com) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Bridget Kennedy
Ranch Hand

Joined: Nov 30, 2004
Posts: 84
I guess the truth is, the view is always potentially outdated as soon as it is displayed. Which brings up another issue - how dynamic is the client view supposed to be? My initial implementation has the view update intiated by client actions. There is no server-to-client push. Maybe this is weak.

Your 'RecordNotFound exception' solution makes sense to me for the situation posed regarding a delete operation. Suppose you have a scenario where the queued operations are both record updates. Say client A is booking record x. Client B is locked out, but gets the lock upon completion of client A's action. What should happen next? Client B books record x, effectively cancelling client A's action? This just doesn't seem right to me - especially considering, at the time the competing request is queued, client B is not aware of client A's booking.

I was originally thinking that locks should only be granted on unlocked records. Clients would display a dialog indicating the record was currently locked by another user - creating an operational environment where clients had to wait and see what others were doing to a record prior to intiating a data-modification action on the same record. That kind of a system doesn't seem to fit with the spec - and certainly violates the 'consumes no cpu cycles until the resource is available' stipulation.
Anton Golovin
Ranch Hand

Joined: Jul 02, 2004
Posts: 476
Bridget, the update and delete operations must be conducted on locked records. Sometimes, the read operation is usefully conducted on a locked record; sometimes, on an unlocked one. The create method must be implemented with care because of its own specificity to undermine the locking mechanism. Those are the general considerations. Hope they are useful. I am not exactly sure if I am answering your question, though, so please feel free to ask anything else you might want to know.
Anton Golovin
Ranch Hand

Joined: Jul 02, 2004
Posts: 476
Originally posted by Bridget Kennedy:
I'm having a little trouble with the spec in the area of record locking and thread management. I infer from the spec that clients queue up for access to specific records. I'm not sure what level of complexity is expected for managing the queue. For example, it seems to me that, operationally, you might run into trouble if thread A has a lock on record x for the purposes of performing a delete. Thread A finishes the delete, releases the record x lock, whereupon thread B siezes the lock to perform an update on record x. Is it a problem since record x is now a deleted record? At the time thread B initiated the update, it was a legitimate operation. While waiting, it became illegitimate. Is it illegitimate? Is it ok to usurp prior actions?

I tend to fall back on the notion that I probably won't get dinged for providing too much complexity. But I don't want to spend time unnecessarily on sophisticated solutions.

Thoughts and/or links to prior discussions of this issue will be most appreciated.


In this respect, after waiting in the lock method, the lock method must check if the record still exists; if not, throw the RecordNotFoundException in the lock method. The code must never get to the update method in your business code.
Jared Chapman
Ranch Hand

Joined: Feb 23, 2004
Posts: 81
Suppose you have a scenario where the queued operations are both record updates. Say client A is booking record x. Client B is locked out, but gets the lock upon completion of client A's action. What should happen next? Client B books record x, effectively cancelling client A's action? This just doesn't seem right to me - especially considering, at the time the competing request is queued, client B is not aware of client A's booking.


Client B shouldn't be allowed to book the record. First, client B tries to get a lock, but is forced to wait for client A to release the lock. Client A books the record and then releases the lock. Client B then locks the record. Once client B has the lock, it then reads the record to ensure that it isn't booked. Since client A just booked that record, client B will see that the record is already booked. So client B then releases the lock WITHOUT booking the record, and takes action to inform the user that the record is already booked.
Jim Janssens
Ranch Hand

Joined: Sep 24, 2004
Posts: 210
Well, I cannot agree with this, I think TS is totally right with his questions and they are not answered in the 'general' threading solution topic. I didn't think about these problems either, so thanks for posting this

This is going to be a long post, so I'll do my best to make it as clear as possible. First of all I distinguish 2 levels of this data 'ensurance' .

The first level is the one where no actions occur at the same time. This means that user one does a read, 5 minutes later user b does a read, one minute later he does an update and again 5 minutes later user a updates his version. So no queue or waiting was necesairy for this example.

To properly handle level one, I created an up to date check in the update and delete method. this means that I do NOT delete or update without checking the CURRENT situation of the database. So, if user one wants to update the record I get the real data of that record (not only the record number) so user one is giving me the data BEFORE the update of user two. I lock the record and read its data. The data will not equal , so I know user a did not saw the latest version. I return an 'out of synch' which tells that he needs to do an re-read first, before he can continue doing the update.

The same story with the delete, when someone wants to delete, I lock first, read the database, check if the supplied data is still consistent with the one in de db , delete if true , out of synch otherwise.

This is pretty straight forward, I want that the user uses the latest version before he can do any kind of manipulation.

The second level is the one where multiple request are handled at the 'same' time. Meaning that both user one and two are doing the update (but with different data) at the same moment. The first level will fail to notice this (in very rare occasions, but it can happen) since the thread of user two can pass the up to date check before user one has written his update, then user two will be added to the queue and wait until user one finishes and then afterwards do his update.

This is a reasonably complex matter. The real problem in choosing the correct solution is matching it with your business logic, this you would do in real world situation. Let me try to explain what I mean:

You cannot directly deny the second update, since that would go against the assignment requirements (however, in a real world application, you might want to do this when the business logic is critical). But for this situation, just identify fields and operations which are crucial to your business, and MUST be taken into account when someone else updates it.

I will give some examples of operations and fields that I can identify:
(keep in mind that these are operations ALREADY in the QUEUE ! and are not level one)

1.delete 2.update cannot happen, no matter the fields entered of changed into the update. You simply cannot update something that has just been deleted. In this case the update should fail and return a message to the user. He should then manually find out who has deleted it and why.

1.update 2.delete may not happen if the update, updated the 'owner' field from nothing to something. Meaning that you can not safely delete a record currently assigned. Again, the user should seek who has updated it and find out if it should be really deleted or not. If other fields are updated, like the name or something, I don't really see a problem why this record cannot be deleted. The user updating the record changed the name because the contractor changed name, but maybe the second user is doing the same thing, but he does a delete first and then a create. Either way, its no real problem as long as the record is not booked.

1. update 2. update

also the owner field, when the first update set it and the second empties it, the second update should be cancelled. When the first thread changed the owner field and the second thread changes it again, also cancel the second update. For all other fields, we don't care.

1.delete 2.delete

cancel 2 (record not found)

Now, one final note:

I'm really concerned about these solutions, basicly they return exceptions from time to time indicating something is out of synch. Which is good. But is it good for the assignment ? Supose SUN fires 100 threads for testing and all of them update the same record, then ofcourse, exceptions are likely to be thrown (out of synch) is this bad ? ...

For example, when you launch 100 updating threads, then about 99% (I'm guessing, but I wont be far of) will be stopped by level one telling the update is out of synch. Only a small amount will make it to the queue...
[ December 01, 2004: Message edited by: Koen Serneels ]
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11424
    
  85

Hi Koen,

I suspect you may be overcomplicating this. Consider the following bit of psuedocode:

Now to consider your two scenarios:

Originally posted by Koen Serneels:
The first level is the one where no actions occur at the same time. This means that user one does a read, 5 minutes later user b does a read, one minute later he does an update and again 5 minutes later user a updates his version. So no queue or waiting was necesairy for this example.


In this case, when client 2 attempts to run the book() method, it will fail at step 3 - the verification of the data. So the second client cannot book the record.

Originally posted by Koen Serneels:
The second level is the one where multiple request are handled at the 'same' time. Meaning that both user one and two are doing the update (but with different data) at the same moment. The first level will fail to notice this (in very rare occasions, but it can happen) since the thread of user two can pass the up to date check before user one has written his update, then user two will be added to the queue and wait until user one finishes and then afterwards do his update.


In this case, we have the security of the Data.lock() to ensure that these two clients do not overwrite each other. According to the specification for the lock method, only one client can own a lock at any given time, and all other clients must block until the lock is released. So when client 1 starts an update, client 2 will block at the call to lock(). When client 1 has completed the update, it will call unlock() at which time client 2 will unblock and then it will fail on the verification stage.

Does this make it simpler?

Regards, Andrew


The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Jim Janssens
Ranch Hand

Joined: Sep 24, 2004
Posts: 210
Yeah ok. So, can you also say this:

Is it ok with the assignment rules that if I have 4 updates at the same time, meaning that one thread is doing the actual update and 3 threads are waiting for the lock, that the 3 other trheads will be canceled ?

Pseudo:

Update: oldRecord,newRecord
1 obtain lock
2 read database
3 if record in database = oldrecord
4 update newrecord
5 else
6 throw outofsynch
7 release lock

Thread one got the lock and the other three threads are waiting by line 1. After thread one finishes the update it releases the lock and thread two will refresh the record from the database (line 2) and see if it still matches the original record which should be updated (line 3) . But this will no longer be the case since thread one updated the record already, thus an out of synch will be trhown. The same story for the other 2 records.

So basicly the assignment has been followed, since there is a lock/wait system for threads wanting to do multiple actions on the same record. But there is no simultanous updating, because more then one update at the same time will fail due to out of synch...

is this the way to go ?
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11424
    
  85

Hi Koen,

My reading of the instructions would indicate that this is the way to go.

Regards, Andrew
Bridget Kennedy
Ranch Hand

Joined: Nov 30, 2004
Posts: 84
Thanks for the helpful dialog.
Daniel Simpson
Ranch Hand

Joined: Sep 02, 2004
Posts: 181
Originally posted by Andrew Monkhouse:
Hi Koen,

I suspect you may be overcomplicating this. Consider the following bit of psuedocode:

Hey Andrew, if I am correct, verifying the record integrity would be checking the "owner" field in B&S to check whether there is a an 8 digit customer ID or not. Is this correct?


SCJP 1.4<br />SCJD 1.4
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11424
    
  85

Hi Daniel,

Hey Andrew, if I am correct, verifying the record integrity would be checking the "owner" field in B&S to check whether there is a an 8 digit customer ID or not. Is this correct?


As a minimum I would recommend checking that there is no customer ID and the record has not been deleted (that's an easy check to miss )

From memory you are planning to minimize network traffic by only passing values you want changed - all other items in your array are null. This, unfortunately, precludes testing to see if the record is still the same record. For example:
  • Client A reads record 5 which happens to be for something in "Smallville"
  • Client B deletes record 5
  • Client C creates a new record for something in "Nashville" (it happens to get written to record 5)
  • Client A updates record 5


  • According to your logic, record 5 is not currently booked, so this will be accepted, even though it is almost certainly not what the customer wanted.

    However it is allowed for in the specifications

    We have had many discussions before in this forum about what is required in order to pass, and what many of us believe we should do in order to produce a professional result. This is one of those areas where I think that as a professional, we must at a minimum consider these sorts of effects.

    Your instructions probably tell you that the create method may overwrite a deleted record. And you might choose to ignore that and just create new records at the end of the file (many do). So the issue I mentioned above might not be applicable to you. But you should still give consideration to it, and make note of it in your design decisions document.

    My personal view is that I think that a project like this could be split in the future, with different people working on different aspects - someone could be working on the database, while someone else works on the GUI. If the person working on the database decides to change your implementation of the create method, then your booking method could break. To me, this implies a lack of future proofing. I would rather have the extra few bytes transferred at the time of booking (and there will be far fewer bookings than reads anyway, so you are not saving that much overall) and have the ability for the Data class to be enhanced at a later date.

    Regards, Andrew
    Daniel Simpson
    Ranch Hand

    Joined: Sep 02, 2004
    Posts: 181
    Hey Andrew, are you also replying to my other post I made about the create method? I was just a little confused with your post. What exactly do you mean when you said:

    I would rather have the extra few bytes transferred at the time of booking (and there will be far fewer bookings than reads anyway, so you are not saving that much overall) and have the ability for the Data class to be enhanced at a later date.
    What part of the code were you referring to for this?

    Also, I know that all of the methods in the DB interface need to be implemented correctly, but I know that the client for this specific application will only have access to a DBAdapter class I have that has a book method, which hides the methods of my data class. I'm not saying I should shrug off implementing the methods correctly and efficiently, but I know that going beyond what is needed will not earn me extra points. However, do you think they will run a lot of tests on our create, delete, etc. methods as a part of the exam grading? Thanks!
    [ December 02, 2004: Message edited by: Daniel Simpson ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11424
        
      85

    Hi Daniel,

    I was referring to your "Writing into DB File" topic, in which you descibe your update method.

    I assumed (possibly incorrectly) that since the update method allows for you to pass empty fields, then you might be passing empty fields to your booking method. If this is the case, then your verification cannot validate those empty fields.

    Regards, Andrew
    Daniel Simpson
    Ranch Hand

    Joined: Sep 02, 2004
    Posts: 181
    Originally posted by Andrew Monkhouse:
    Hi Daniel,

    I assumed (possibly incorrectly) that since the update method allows for you to pass empty fields, then you might be passing empty fields to your booking method. If this is the case, then your verification cannot validate those empty fields.

    Regards, Andrew


    Hey Andrew, I'll try to explain my reasoning for my update method. Say a user only wants to update the contractor's location. All they would have to put into the data values would be {null, "new york", null, null, null, null}. That way, when updating the database, it will only update that specified field and all of the other values will be untouched. It seems redundant for a user to have to supply all of the information for the entire record, just to update one field, and then overwrite every value. If the value is null, then that field will not be overwritten, and whatever was the last value for that field will remain that value. So when I call my book method and have a data value verification, it will test all of the records with the values in them. The only possible field that could be blank would be the customerid field, which of course will not be tested. I hope that helps explain my reasoning. Thanks for all of your help, Andrew!
    Rafael Forte
    Greenhorn

    Joined: Dec 07, 2004
    Posts: 8
    But in this case we have a specification contradiction: The DBAccess interface says to throw a SecurityException if the lockCoockie is invalid, but this sitiuation clearly doest't happen because any attemp to lock the updating record will be stoped in Object.wait(). In short, two threads will never execute the updateRecord method for the same recordNumber.

    It seems to be more an assummption in the design choices.

    Regards,
    Rafael Forte.
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11424
        
      85

    Hi Rafael,

    Your assumption is reasonable for your code, however there is nothing to say that somebody else's code is going to be so well behaved. It is theoretically possible that someone else could look at the contract provided by the interface, and decide to write their own application which directly uses your Data class. And they might decide not to bother with lock cookies. Your update method should catch this error in the other programmer's logic, and throw the security exception.

    Regards, Andrew
     
    Don't get me started about those stupid light bulbs.
     
    subject: data locking; competing actions