• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Post Database lock scenario

 
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,
We have to implement lock(-1) to impose DB lock.
I am doing this by recursively calling lock() on each record. This will allow all clients those already acquired locks on records to finish their job.
But if some clients try to lock the records after the DB lock is imposed, they have to be in waiting pool indefinitely. In order to avoid this situation, I am keeping a static boolean isDbLocked(intially set to "false" and changed to true if lock(-1) called) and a non-static Object reference dbLockingClient(initially set to null, if lock(-1) called, it will change its value to "this") - in the RemoteData.
In the lock() method od RemoteData, I check
if ((isDbLocked) && (dbLockingClient != this))
then it will throw a DatabaseException saying that the database is locked for maintenance.
I am not sure whether this approach is good or not. How did you all handled this situation??
Thanks,
Padmaja.
[ May 21, 2003: Message edited by: Padmaja Prasad ]
 
Padmaja Prasad
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Please...
 
author and jackaroo
Posts: 12200
280
Mac IntelliJ IDE Firefox Browser Oracle C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Padmaja,
In FBNS, the call to lock should be a blocking call. So I have treated a database lock like every other lock (except with higher priority) - once a database lock is aquired, all other clients have to wait till it is released before they can aquire their lock.
If the database was locked because of a shutdown, then the other clients will not get their lock, and will eventually get an exception when the server shuts down.
If the database was locked in order to perform an addition to the database or some other major change, then when the change is complete, then the clients will start aquiring locks again.
I am not sure about the following bit of code:
if ((isDbLocked) && (dbLockingClient != this))
Are you implying that the client who locks the entire database might then try and lock individual records? Otherwise I cannot see the point in checking who is doing the locking.
I think your two variables are essentially duplicating each other, so you could reduce this to:
if ((dbLockingClient != null) && (dbLockingClient != this))
Having two variables performing the same function is (IMHO) a bad thing - you have a risk that the junior programmer modifying your code next misses the fact that there are two variables to be updated at the same time, and your code could break in a hard way to debug.
Are you maintaining a Map or Set which corresponds directly to the database? So you have one item in the map or set for every record in the database regardless of whether the record is locked or not? This implies that you have to add records to the map / set if a client calls the add() method. I just added and removed items from my set on the fly as clients called lock and unlock. So if someone locked record 5, I would add Integer(5) to my set. If it exists in the set then the record is locked. When they unlock it, I just remove that Integer. Doing it this way means that locking the database becomes just another add to the set where I am adding Integer(-1).
Regards, Andrew
 
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
... I am doing this by recursively calling lock() on each record. This will allow all clients those already acquired locks on records to finish their job.
But if some clients try to lock the records after the DB lock is imposed, they have to be in waiting pool indefinitely. In order to avoid this situation, I am keeping a static boolean isDbLocked(intially set to "false" and changed to true if lock(-1) called) and a non-static Object reference dbLockingClient(initially set to null, if lock(-1) called, it will change its value to "this") - in the RemoteData.

then it will throw a DatabaseException saying that the database is locked for maintenance.

You seem to be taking two different db lock schemes and combining them into one. If you are recursively locking all records when a db lock is requested then why do you need to maintain a boolean indicating that the db is being locked. Conversely, if you maintain a boolean why then do you need to lock every record? Why also do you need to throw an Excpetion if the db is being locked? Just let the requesting clients go into the wait state. If the server is shut down after the db lock (which would be the major reason for locking the db) then each client will receive a RemoteException at some point. If the lock is only for some temporary maintainence, then the clients will be none the wiser.
Remember that your locking does not have to be bullet proof. I would advise that you choose one scheme or the other, either keep a static boolean to indicate the state of the db lock or recursively lock each record and just allow every thing else to flow as normal and don't worry about clients in the wait pool.
 
Padmaja Prasad
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Andrew,
Thanks for the reply.
Actually my lock & unlock are done by a lock manager class which has a Hash map to keep track of who locked which record etc.


If the database was locked in order to perform an addition to the database or some other major change, then when the change is complete, then the clients will start aquiring locks again.


So all the clients have to wait untill the server processes are complete??


I am not sure about the following bit of code:
if ((isDbLocked) && (dbLockingClient != this))


isDbLocked is a boolean indicating whether a database lock is requested or not.
dbLockingClient is the RemoteData object which requested a db lock. As my lock(-1) implementation call recursively lock(recordNum) on each record, only "this"(current thread) instance of RemoteData is allowed to finish locking. Other threads trying to lock a record should receive an exception.


I think your two variables are essentially duplicating each other, so you could reduce this to:
if ((dbLockingClient != null) && (dbLockingClient != this))


Yeah..you are right.


Are you maintaining a Map or Set which corresponds directly to the database? So you have one item in the map or set for every record in the database regardless of whether the record is locked or not? This implies that you have to add records to the map / set if a client calls the add() method. I just added and removed items from my set on the fly as clients called lock and unlock. So if someone locked record 5, I would add Integer(5) to my set. If it exists in the set then the record is locked. When they unlock it, I just remove that Integer. Doing it this way means that locking the database becomes just another add to the set where I am adding Integer(-1).


Nope..Only my lock manager class has a hashmap for holding the locked record's number. lock(-1) is handled at RemoteData which calls its lock method recursively.

Thanks,
Padmaja.
 
Padmaja Prasad
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Michael,


Remember that your locking does not have to be bullet proof. I would advise that you choose one scheme or the other, either keep a static boolean to indicate the state of the db lock or recursively lock each record and just allow every thing else to flow as normal and don't worry about clients in the wait pool.


Thanks Michael... I'm also planning to leave the clients in the wait pool when they request lock after db lock is imposed.
Regards
Padmaja.
 
Ranch Hand
Posts: 70
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, padmaja,

Actually my lock & unlock are done by a lock manager class which has a Hash map to keep track of who locked which record etc.


Do we really need to keep the id who locked the record? I think it is not necessary. Andrew mentioned set. I know someone used vector. These are simple and good enough.
 
Michael Morris
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Do we really need to keep the id who locked the record? I think it is not necessary. Andrew mentioned set. I know someone used vector. These are simple and good enough.
There is a requirement that an unlock request should be ignored if a requesting client does not own the lock. So if you don't somehow map the client to the lock, how can you meet that requirement? What if, heaven forbid, someone introduces a subtle bug in your client code that rarely requests an unlock on a record that it does not hold the lock for? Further suppose that two other clients are vying for that lock, one of which has acquired it and the other is waiting. Now when the rogue client unlocks the record the waiting client grabs the lock and proceeds to book seats that the first client has already taken. Obviously that is not a very likely scenario, but it could happen and somebody is going to be very pissed when their seat is already taken.
 
shan chen
Ranch Hand
Posts: 70
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Michael,
Thanks for your reply. I just checked my instruction and did not find the requirement you mentioned: "An unlock request should be ignored of a requesting client does not own the lock." My assignment is new version hotel room booking. I hope someone else with the same assignment could check their instructions to help me to verify it. If such requirement exists, we DO neeed client ID.
For the next two questions, I will write in choices.txt that it is assumed those situation will not happen.
 
Padmaja Prasad
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Shan,

Originally posted by shan chen:
Hi, padmaja,

Do we really need to keep the id who locked the record? I think it is not necessary. Andrew mentioned set. I know someone used vector. These are simple and good enough.


Yup, we need to keep id of the client locking a particular record as per the SCJD requirements. Refer Michael's reply. Also do a search on this forum for LockManager. You will understand the need for that.
 
Michael Morris
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My assignment is new version hotel room booking.
I was assuming that you were referring to the Fly by Night assignment. So in your case, if there is no requirement to verify the lock owner on an unlock, then a Set would be a better choice of data structure to hold the locked records.
 
Andrew Monkhouse
author and jackaroo
Posts: 12200
280
Mac IntelliJ IDE Firefox Browser Oracle C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Padmaja,
(Shan: FYI, the clause in the Fly By Night Services is: If an attempt is made to unlock a record that has not been locked by this connection, then no action is be taken.)
Padmaja, the way you are doing it is fine, and many others also do this.
Just to give you an alternate to think about though, I have put the lock owner verification right at the RMI Interface. In my case, the Data class is only concerned with whether the record is locked, not who locked it. The RMI interface keeps track of which records were locked by this connection and simply ignore any attempt to unlock a record that this connection did not lock.
The disadvantage is that I am now tracking locks in two different places: in the RMI code and in the Data class.
The advantages are:
  • when unreferenced gets called, the RMI code knows explicitly which locks it has to unlock
  • the mechanism for identifying who the owner of the lock is, is kept away from the Data class. If you have the Data class track this, then you either have to use the thread to track the user, or you have to change the signature of lock method. If another networking solution was added that didnt really work well with having a thread dedicated to each connection (say MQ), then you would have to try and force it to work with threads in your case - in mine, I just have to work out what does work with the new networking solution, and keep it in the networking code

  • Regards, Andrew
     
    Padmaja Prasad
    Ranch Hand
    Posts: 76
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Andrew Monkhouse:
    Hi Padmaja,
    Padmaja, the way you are doing it is fine, and many others also do this.
    Just to give you an alternate to think about though, I have put the lock owner verification right at the RMI Interface. In my case, the Data class is only concerned with whether the record is locked, not who locked it. The RMI interface keeps track of which records were locked by this connection and simply ignore any attempt to unlock a record that this connection did not lock.
    The disadvantage is that I am now tracking locks in two different places: in the RMI code and in the Data class.
    The advantages are:

  • when unreferenced gets called, the RMI code knows explicitly which locks it has to unlock
  • the mechanism for identifying who the owner of the lock is, is kept away from the Data class. If you have the Data class track this, then you either have to use the thread to track the user, or you have to change the signature of lock method. If another networking solution was added that didnt really work well with having a thread dedicated to each connection (say MQ), then you would have to try and force it to work with threads in your case - in mine, I just have to work out what does work with the new networking solution, and keep it in the networking code

  • Regards, Andrew


    Well, as per my design, I have one "non-static" Arraylist that holds all record numbers locked by the current thread. In unrefernced method, I called unlock() on all items in this array.
    I have implemented lock()/unlock() only in Remote mode and not in Dataclass. My locking/unlocking are done by LockManager class. So it is seperated from the Data class.
    I'm almost finished my project..and everything is working fine.
    Regards
    Padmaja
     
    Michael Morris
    Ranch Hand
    Posts: 3451
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    AM: The disadvantage is that I am now tracking locks in two different places: in the RMI code and in the Data class.
    I don't see that as much a disadvantage as just a natural design decision. Each client should have it's own RMI object for interacting with Data. Where better to track each client's locks and verify the lock state? I used a LockManager and did not alter the Data class aside from some cosmetic changes like adding javadoc comments. All the locking logic was controlled by the RMI object and the LockManager. Data's lock and unlock were left unimplemented.
     
    shan chen
    Ranch Hand
    Posts: 70
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi,
    I am a question about RMI remote object here. How many remote objects will be generated for multiple clients?
    Michael said its own RMI object. Do you mean one remote object for each client?
    Padmaja said I have one "non-static" Arraylist that holds all record numbers locked by the current thread.. Where is the Arraylist? In the remote object?
    Andrew said The RMI interface keeps track of which records were locked by this connection
    Do you also imply one remote object for each client?
    My understanding is there is only one remote object on the server side. Remote object is
    pass-by-reference to the client. Stud is sent back and forth.
    I have done the following test: add a static variable to the remote object class, the static variable increses by one in the constructor. When I run the program, the static variable keeps as one even though multiple clients have connected to the server.

    shan
     
    Michael Morris
    Ranch Hand
    Posts: 3451
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Michael said its own RMI object. Do you mean one remote object for each client?
    That's the best way. You should use a Factory to create a new object for each client. Just think about the threading problems and chaos you would have if every client interacted with the same remote object.
    Padmaja said I have one "non-static" Arraylist that holds all record numbers locked by the current thread.. Where is the Arraylist? In the remote object?
    I can't speak for Padmaja but I used a Map in my LockManager to map clients to locked records, I also maintained a Set of locked records in each of the client remote objects.
    Andrew said The RMI interface keeps track of which records were locked by this connection
    Do you also imply one remote object for each client?
    Once again, I can't speak for Andrew, but I would guess that is exactly what he means. The Factory pattern for RMI applications is very common.
    My understanding is there is only one remote object on the server side. Remote object is
    pass-by-reference to the client. Stud is sent back and forth.
    If you implement a Factory pattern, then yes there will be one remote object bound to the registry that each client will connect to. That remote object should have a method like getConnection() which will return a unique DataAccess (or whatever you call it) object to the calling client.
     
    shan chen
    Ranch Hand
    Posts: 70
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi, Michael,
    Thanks for your reply. Now I understand your design. My implementation is different, so I did not realize this at first, sorry. Can I make some comments? I deem it a chance for me to learn something.

    Just think about the threading problems and chaos you would have if every client interacted with the same remote object.


    I think it is the merit of RMI. RMI handles multi-threading issues. That is one of the reasons I chose RMI.

    That remote object should have a method like getConnection() which will return a unique DataAccess (or whatever you call it) object to the calling client.


    According to RMI policy, the DataAccess object passed to client is pass-by-value. In the case that the client want to call 'book', will the client call DataAccess directly or through the remote object?
    Thanks.
    Shan
     
    Andrew Monkhouse
    author and jackaroo
    Posts: 12200
    280
    Mac IntelliJ IDE Firefox Browser Oracle C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Shan


    Andrew The RMI interface keeps track of which records were locked by this connection
    Shan Do you also imply one remote object for each client?
    Michael Once again, I can't speak for Andrew, but I would guess that is exactly what he means. The Factory pattern for RMI applications is very common.


    Yes, that is exactly what I meant. Once I finally understood what everyone was suggesting it all made so much sense, and I went with the factory pattern.


    Shan According to RMI policy, the DataAccess object passed to client is pass-by-value. In the case that the client want to call 'book', will the client call DataAccess directly or through the remote object?


    Your code will call DataAccess directly.
    The client code really doesnt look much different between having one remote object for everyone and having a factory that provides remote objects per client.

    Compared with:

    The factory is simplicity itself - it just returns an instance of DataAccess.
    Regards, Andrew
     
    shan chen
    Ranch Hand
    Posts: 70
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks, Andrew. Now I know the differences. My implementation is the first version. It is nice to see how Factory Pattern implemented with RMI.
    shan
     
    Consider Paul's rocket mass heater.
    reply
      Bookmark Topic Watch Topic
    • New Topic