aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes UrlyBird 1.3.2 locking with no cookie 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 "UrlyBird 1.3.2 locking with no cookie" Watch "UrlyBird 1.3.2 locking with no cookie" New topic
Author

UrlyBird 1.3.2 locking with no cookie

Matt Earl
Greenhorn

Joined: Feb 28, 2007
Posts: 8
I am almost about to submit my project, however I have got a bit worried that my locking strategy is wrong.

I originally had a singleton class Data.java which had a static reference to a RAF and had a static ArrayList object which held the locks.



The problem as I now see it is that in theory another client can unlock a locked record as there is no record of the "locker".

I have though that maybe I can have a Hashtable instead of a List to store locking information and put in the recNo and the Thread ID.


The problem with this is how should I handle the unlock situation?


My DBMAIN interface has no other exception to throw other than RecordNotFoundException and this seems wrong, and the method signature is void so I can't even return a boolean. Any ideas?


Tottenham Hotspur - Pride of North London
Romeo Son
Ranch Hand

Joined: Mar 12, 2007
Posts: 92

Hi,

I have thrown a RuntimeException("Thread is not lock owner for record " + recNo).
You can extend RuntimeException and give a meaningful name.
This way I don't let a thread that didn't lock previously the record to unlock it.

Regards,

Romeo


SCJP 1.4, SCJD, OCE EJBD 6
Herman Schelti
Ranch Hand

Joined: Jul 17, 2006
Posts: 387
hi Matt,

I am reading "SCJD Exam with J2SE 5" and it says on page 151:
"The RMI specification states that there are no guarantees about which threads will be used for any given remote method."

So I think using Thread.currentThread().getID() won't help you.

The autors give a solutions later in the book, but I haven't read that yet.

Herman
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Herman Scheltinga:
hi Matt,

I am reading "SCJD Exam with J2SE 5" and it says on page 151:
"The RMI specification states that there are no guarantees about which threads will be used for any given remote method."

So I think using Thread.currentThread().getID() won't help you.

The autors give a solutions later in the book, but I haven't read that yet.

Herman


The way around this problem is to document that lock, update, unlock must be carried out in a the same thread of execution via a single RMI call. The best way to do this is through the use of a facade or adapter class with a book() method or else the use of an adapter class with an update method that performs the lock -> update -> unlock sequence automatically.

I don't think that it is a very efficent solution to make an RMI call to lock a record, another to update the record, and a final call to unlock the record. The time it would take for these calls to traverse the network would mean clients could be waiting a long time compared to performing the locking sequence directly on the server.

It is not an ideal solution but if you are given a version of the project that has no lock cookies it is preferable to not doing any checking at all.


SCJP<br />SCJD
Lucy Hummel
Ranch Hand

Joined: Apr 07, 2005
Posts: 232
Hi,

I totally agree that the unlock and lock should be done by the business layer on the server so that the facade just provides a book method that the client calls. The book method takes care of lock and unlock.


----------------------------------<br />| SCJP, SCWCD, SCBCD, SCEA, SCJD |<br />----------------------------------
Maurizio Nagni
Ranch Hand

Joined: May 29, 2004
Posts: 75
yeah... i agree, and implemented, to use a facade to create a more "human understandable" action BUT be carefull.
Suppose your book method in the facade class do the following




if you look at it carefully you will find that even if all the methods of the data class are synchronized book() is NOT! to this i found two solution

1) synchronize all the book() method.... unfortunately it create a slow down performance (yes.. ok... we do not have to care about performance)

2) wrap all in a new thread like
book() {
new Thread() {
void run() {
//yourCode
}
}
thread.start();
thread.join();
thread = null; //avoid memory leakage
}

please sorry the real raw format, but i would not be accused to pass code around
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Maurizio Nagni:
yeah... i agree, and implemented, to use a facade to create a more "human understandable" action BUT be carefull.
Suppose your book method in the facade class do the following




if you look at it carefully you will find that even if all the methods of the data class are synchronized book() is NOT! to this i found two solution

1) synchronize all the book() method.... unfortunately it create a slow down performance (yes.. ok... we do not have to care about performance)

2) wrap all in a new thread like
book() {
new Thread() {
void run() {
//yourCode
}
}
thread.start();
thread.join();
thread = null; //avoid memory leakage
}

please sorry the real raw format, but i would not be accused to pass code around


Perhaps I am missing something but if the data class is thread safe then it should not matter that the book method is synchronized or not?

Suppose two threads call book(2) then the thread that makes it to the lock first gets to proceed while the other one gets blocked in the lock method of Data. When the other thread gets the lock it will find that the record is locked and return an error to the user.

If two threads are executing book method on different records then they ought not to interfere with each other as long as the update method is implemented in a thread safe fashion also ie synchronized RAF or local RAF.
Maurizio Nagni
Ranch Hand

Joined: May 29, 2004
Posts: 75
well.... in a simple case if you have



if the second thread enter meanwhile i am doing "something" it will overwrite the lock value and when the first thread will enter in update... well.... CRACK!

what you say can be true in special situations but i preafer to have a global insurance
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Maurizio Nagni:
well.... in a simple case if you have



if the second thread enter meanwhile i am doing "something" it will overwrite the lock value and when the first thread will enter in update... well.... CRACK!

what you say can be true in special situations but i preafer to have a global insurance



But if the lock value can be overwritten then its not doing its job properly and isn't really a lock method at all. It is the job of the lock method to stop ANY thread from progressing any further if the record they are interested in is locked and they should not do anything else excepts occasionally check if the correct lock is available when notified.
[ May 10, 2007: Message edited by: Mark Smyth ]
Maurizio Nagni
Ranch Hand

Joined: May 29, 2004
Posts: 75
I am talking about two different threads on two differents records.
The task of the lock is to forbidden two threads to operate on the same record BUT should be transparent if the threads are operating on different records.
Consequently the code I wrote in the previous post (lock, doSomething, update) require some kind of control because the lock stop the second thread if it want a record already locked not an available one.
Romeo Son
Ranch Hand

Joined: Mar 12, 2007
Posts: 92

Hi,

I have a question about the book method.
In the book you don't have also a read before update, to see if the ownerId field is empty or not? (if booking is alowed or not)?
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Maurizio Nagni:
I am talking about two different threads on two differents records.
The task of the lock is to forbidden two threads to operate on the same record BUT should be transparent if the threads are operating on different records.
Consequently the code I wrote in the previous post (lock, doSomething, update) require some kind of control because the lock stop the second thread if it want a record already locked not an available one.


I agree that the lock method should be transparent if the threads are operating on different records. Even so the update method similarly ought to be be able to cope with two threads to working on different records without affecting each other.

To understand your position better perhaps you could explain a scenario you where you believe two threads working on different records may interfere with each other (Your do something scenario menioned in the previous posts). Perhaps I not considering something that is obvious to you or we have two very different solutions to the problem .
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Romeo Son:
Hi,

I have a question about the book method.
In the book you don't have also a read before update, to see if the ownerId field is empty or not? (if booking is alowed or not)?


Yes there ougth to be a read after the lock to ensure that the record has not been booked. If the read occurs before the lock then two records might check the record, see it is free and both will proceed to book the record with the second thread overwriting the first.
Maurizio Nagni
Ranch Hand

Joined: May 29, 2004
Posts: 75
nice discussion sorry Mark if i was not so clear... anyway the situation i am thinking is this: 2 Classes
1) facade (contain the book method)
2) data (contain the implementation of the lock, update, etc...)

suppose this simple situation take 3 Thread, T1, T2, T3, that want to lock three different records, R1, R2, R3

in the facade we have the book method as usual:

book(recNum) {
x = data.lock(recNum)
d = doSomething();
data.update(x, d)
}

now....
T1 enter in book and lock R1
T1 doSomething
T1 enter in update and (for misterious reason it stay that for a looooong time)
T2 enter in book ad lock R2
T2 enter and doSomething
T2 cannot enter in update because actually busy (i suppose that a write operation lock the file)
T3 entert in book and lock R3
T3 doSomething and waits for update to be free

now.... which value will have "d" for T2 and T3? i say the same value.

The point is that the facade class is done to really define the operation of booking (in data there are only the atomic operations) and so in general you cannot suppose to have only, lock and update and because it is the server frontline all the threads will pass throught it and so better to be ready for the crowds. I made a small class to test my urlybird: using more than 100 clients (thread) asking for almost 1000 operations each... well.. taking care of how the facade take care of the several threads change dramatically the result

ciao
Romeo Son
Ranch Hand

Joined: Mar 12, 2007
Posts: 92

Hi Mark,

I have simply synchronized the book method, so I do the read before the lock and I think it's OK also my approach, correct?

Romeo
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
I am afraid I will have to disagree again my friend, isn't debating fun? . If you use locking to ensure that two threads cannot be updating the same record at the same time then you can also ensure that it can be perfectly safe that multiple threads can be using the update method to alter different records at the same time, of course there are certain safeguards that you have to take to ensure this.

The reason that multiple threads can use the update method at the same time is due to the fact that the files contain fixed size records. Lets say for arguements sake that the size of a record is 80 bytes.

Suppose we have two threads A and B. A is trying to update record 0, and B is trying to update record 1.

A->book(0)
B->book(1)

A and B get to the lock method around the same time, both have no problems obtaining their respective lock and both find that the records have not been booked so they can proceed to the update method to book the records for their respective clients.

At this point threads C and D come along trying to book record 0 and 1 respectively. Once they get here we are agreed that they can go no further until A and B release the lock (the will find the record booked but that is outside the scope of this example.

Back to threads A and B. Because the records are of fixed sizes we can guarentee that threads A and B will be updating different and non overlapping sections of the file. Thread A will be writing to positions 0-79 and thread B from positions 80-159.

Once you ensure that the design endsures the static RandomAccessFile Pointer is synchronized or if you use local RAF instances (one per thread instance) the code will be thread safe and this will not be a problem.
Maurizio Nagni
Ranch Hand

Joined: May 29, 2004
Posts: 75
interesting the part about the fixed lenght record.... i didn't thought about it like an "autosynch" system
ok..ok... i tell you all the story....in my book method i pass as parameters, the record number and the ID of the user: the book method has to create a new record writing the userID which booked it and then pass it to the update(). It cannot be the update method to do that, it only write in the file; it must be done by the doSomething() method of the book() method.

the problem is not in the update but in the d = doSomething(); inside the book method. in the previous case, if T2 and T3 have the same value of "d" (bacause of the lazy T1) and supposing that when update method is available T2 start first, T2 will update a record that may be not what it wants but the cases can be many more... depend your implementation of the doSomething() (or more than just one doSomething)

ciao
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Romeo Son:
Hi Mark,

I have simply synchronized the book method, so I do the read before the lock and I think it's OK also my approach, correct?

Romeo


I must admit I am fundamentally opposed to synchronization of the book method. Sure it is guarenteed to be thread safe, but it is not the most elegant solution. If you synchronize the booking method then only one thread at a time can enter this method regardless of whether or not they are trying to update the same record or a different record. If you have 100 threads trying to book 100 different records then the last one will have to wait for the other 99 to finish one by one until it finally gets to proceed (If you later add in synchronised edit, create and delete methods for example to your facade in the future it gets even worse).

After going to all the trouble of implementing a record locking mechanism then why not use it. There is no need to even call the lock method in the booking method if it is synchronised because the current thread has to be the only one that is writing to the file.


Regards,
Mark
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Maurizio Nagni:
interesting the part about the fixed lenght record.... i didn't thought about it like an "autosynch" system
ok..ok... i tell you all the story....in my book method i pass as parameters, the record number and the ID of the user: the book method has to create a new record writing the userID which booked it and then pass it to the update(). It cannot be the update method to do that, it only write in the file; it must be done by the doSomething() method of the book() method.

the problem is not in the update but in the d = doSomething(); inside the book method. in the previous case, if T2 and T3 have the same value of "d" (bacause of the lazy T1) and supposing that when update method is available T2 start first, T2 will update a record that may be not what it wants but the cases can be many more... depend your implementation of the doSomething() (or more than just one doSomething)

ciao


Could you clarify what the variable "d" is. I am not quite sure how T2 and T3 could have the same values of d if they are operating on two different records. Is d a local varible or a class member variable. If d is a local variable then each thread should have its own stack with its own copy of d that is independant of the other threads.

Am I right in assuming that doSomething read the record, checks the owner id field is blank and then updates the record, or returns an error if it is already booked.

*EDIT* Here is the main parts of my book room method



[ May 11, 2007: Message edited by: Mark Smyth ]
Lucy Hummel
Ranch Hand

Joined: Apr 07, 2005
Posts: 232
Hi,

My booking looks similar to Mark's one.

Wishing a successfully weekend
Romeo Son
Ranch Hand

Joined: Mar 12, 2007
Posts: 92

Hi Mark,

Thanks for your reply. I would have two comments, if I am permitted.

First, about the book method you posted. What happens if you try to lock record 100, that doesn't exists or you get a DataIOException thrown by your lock method? Then in your finally block you try to unlock a record that was never locked. Have you tested this situation, or what is your solution to this? I do in my finally block :


Second, I have thought about what you said about not synchronizing the book method.



Suppose Thread A wants to book record 0 and thread B wants to book record 1.
Suppose record 0 is already booked and record 1 is not.
A gets first CPU so it locks record 0 and reads record 0. Now B gets CPU and locks record 1 and reads record 1. At this time, A gets CPU again and continues from where it has been left, so it tries to update record 0 (remember, 0 it is booked in DB) with the values of record 1 (that is not booked in the DB).
Now A thinks 0 can be booked when in reality it can't be!!!
What do you think about this scenario? I am not convinced about your 100 threads, I think your approach would corrupt the data.
Please comment
Thanks!

Regards,

Romeo
Mark Smyth
Ranch Hand

Joined: Feb 04, 2004
Posts: 288
Originally posted by Romeo Son:
Hi Mark,

Thanks for your reply. I would have two comments, if I am permitted.

First, about the book method you posted. What happens if you try to lock record 100, that doesn't exists or you get a DataIOException thrown by your lock method? Then in your finally block you try to unlock a record that was never locked. Have you tested this situation, or what is your solution to this? I do in my finally block :



My unlock method does not throw RecordNotFoundException. While not an ideal situation it a choice I made to overcome the following problem. You have to lock a record to delete it according to the spec. If you then call unlock the application would throw a RecordNotFoundException when the unlock method is called. I felt that this would not be appropriate behaviour for the application so I dropped it in my Data implementation. Exceptions are however thrown if an attempt is made to unlock a record that was not locked by the same thread.




Second, I have thought about what you said about not synchronizing the book method.



Suppose Thread A wants to book record 0 and thread B wants to book record 1.
Suppose record 0 is already booked and record 1 is not.
A gets first CPU so it locks record 0 and reads record 0. Now B gets CPU and locks record 1 and reads record 1. At this time, A gets CPU again and continues from where it has been left, so it tries to update record 0 (remember, 0 it is booked in DB) with the values of record 1 (that is not booked in the DB).
Now A thinks 0 can be booked when in reality it can't be!!!
What do you think about this scenario? I am not convinced about your 100 threads, I think your approach would corrupt the data.
Please comment
Thanks!

Regards,

Romeo


This scenario could indeed happen if the room object was a member variable of the class however it is in fact a local variable belonging to the method. When multiple threads call the same method each thread has it own copy of its local variables placed on the heap. As a result whatever changes a thread makes to its own copies of the local variables cannot be seen by other threads. Therefore in the above secnario thread A will still have correct record 0 data in the room object when it regains control of the CPU.

Hope this clarifies my intentions behind the code.
Regards,
Mark.
[ May 13, 2007: Message edited by: Mark Smyth ]
Romeo Son
Ranch Hand

Joined: Mar 12, 2007
Posts: 92

Mark,

You are correct, I made a big mistake.
I forgot that each thread has its own copy of the local variables in a method.
I will remove the synchronized keyword from my book method and lock before the read.

Thanks for your reply, you helped me a lot!

Regards,

Romeo
[ May 14, 2007: Message edited by: Romeo Son ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: UrlyBird 1.3.2 locking with no cookie