• 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

Contractors locking question / uncertainty - deadlock possibility

 
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Ranchers,

my interface uses lock cookies. In the specs I have the following sentence:
"Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available."
What I understand by this (especially the "give up the CPU until resource is available") is that I need code like this one:

and in unlock:

However, there is a possibility of a deadlock - if the same client tries to lock the same record twice, sequentiallly: it locks first, then it attempts to lock second time, and the record is locked,(by it!) so it calls await() on the condition. Other clients don't have the lock so cannot help, and if by any chance all other clients want to lock the same record, there is a global distributed deadlock - not nice.

I think I will go for RMI simply because I want to learn it (I use JDK 5 Locks for the very same reason, and I think I will state it explicitly in choices.txt). I am not sure, but I think it is possible that the same thread might be reused by different requests, so by different clients. This prevents me from having code that checks if the record was locked by the same thread as attempts to lock it now to return if the same thread wants to lock the same record - firstly because I will never be sure that the same client / different request will use the same thread (most likely not), and secondly (as mentioned) a different client might use the same thread from the pool or whatever.

What do you say? How can I make it better? Maybe I didn't understand the specs?

What about the awainUninterruptibly() call? Do you think it is good here? I don't have to catch InterruptedException this way - how else do you suggest to deal with it?

Something about my design - the DB uses a single Lock (for simplicity, the specs wants a junior to understand the code and I don't know where a junior draws the line ) to synchronize the reads / writes to the (RandomAccessFile) database. Also, the same lock is used to create a Condition lockTaken (mentioned in the code snippets above) and it is used when LockManager is created. Every LockManager method is called with the Lock acquired, so using the lockTaken Condition is safe. Now, the update() / delete() in DB methods require the lock cookie to match, and it is checked again using LockManager, but it is simple code, no Condition magic there. lock() / unlock() pretty much look like shown above - with some exception handling.

One more thing - the unlock() method specs say:
"Releases the lock on a record. Cookie must be the cookie returned when the record was locked; otherwise throws SecurityException."
I throw this exc when it is attempted to unlock() a record that is not locked. Do you think it is OK? It seems like a security vulnerability to me - after all, you should only unlock() if you know you locked the record and have the cookie to authorize the action.

Do you think it is OK? What are your suggestions?

Regards,
Raf
 
Raf Szczypiorski
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Additional question: my specs say:
"Any methods that throw RecordNotFoundException should do so if a specified record does not exist or is marked as deleted in the database file."

But obviously, this should not happen for lock / unlock, right? Suppose a scenario:
- lock record #17
- delete record #17
- unlock record #17 (so that the slot can be reused)

If I stick strictly to what the specs say, unlock would throw an exception and noone, ever, ever, would be able to lock it, and anyone already waiting on this record will block forever.

What to do, what to do?
 
Sheriff
Posts: 11604
178
Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Raf,

A warm welcome to the JavaRanch!

I will try to clear your doubts a bit:
  • I used none of the new concurrency API of JDK 5, I just used the wait/notify/notifyAll methods. But you can use this concurrency API without any problem.
  • More information about how I handled InterruptedException, can be found here
  • You are correct: RMI doesn't guarantee that same thread will handle all subsequent requests from the same client. In my case I had a thin client (and an interface without the lockCookie), so I was able to throw an IllegalStateException when a client tried to lock another record (the same one or another one) when it was already owning a lock on a record. This is a very common problem/issue about the interface with the lockCookie, so if you use search engine you'll find many threads discussing this issue. But I know of people just documenting in javadoc (and choices.txt) a client must call unlock-method (after locking a record) before trying to lock another one.
  • In my code after any call to lock-method, the unlock-method is invoked (after an update/delete of course), because that's how it is supposed to be used. But the only method in my assignment (besides read and find) which can throw a RecordNotFoundException is the lock-method. The update/delete/unlock methods can never throw a RNFE, because if the lock-method successfully locks a record, nothing can happen with the record and the record will always be there (no other client can delete/update it behind the back of the client which locked the record).


  • Kind regards,
    Roel
     
    Raf Szczypiorski
    Ranch Hand
    Posts: 383
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Roel,

    in the meantime I changed the code to use synchronized blocks as the Lock API was too bloated and it is much more readable now.

    As for the unlocking - I was thinking of creating a thin facade around the DB implementation that has only a few methods (not necessarily the same as the ones as defined in the required interface) and they will call lock - update / delete - unlock in a sequence - this way the client will never call lock itself and so it will never have the option to lock the same record twice, and deadlock. The downside to this approach is that the facade will prevent the clients from more sophisticated uses. For example, It would be nice it the client could lock a given record for as long as it needs, and work with it to be sure it will never be updated by anyone else (in the other approach two clients updating the same record would cause to the first one to have stale data). I don't know if such finer-grained functionality is necessary at all, haven't thought about is yet.

    The good thing is that I tested the class with Roberto's tester and it passed no problem even with 100 000 iterations of the main loop (it lasts a while, though; for 10 000 it takes a minute to complete).

    What about state data? It is not strictly related to locking, but as the discussion goes on, I have already touched on it - do you know if anyone used some automatic refresh (like Observer pattern on the server that after any update would issue an update of given record / a message that an update is needed to all clients that are connected)? Or a refresh button?

    Raf
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Raf,

    creating a thin facade around the DB implementation

    So you are opting for a thin client I created also a business service which acts as a facade around Data class. It just had 2 methods: find and book. It is a valid approach, but according to Andrew Monkhouse it should not be a valid approach. The whole discussion can be read here. But as I said already: you can create a thin client and pass the certification.

    What about state data?

    I guess you mean stale data. I kept my GUI and application as simple as possible, so no observer to refresh data when in another client an update has occured. Also no refresh button. If a user wants "fresh" data, he just has to search for records again.

    Kind regards,
    Roel
     
    Raf Szczypiorski
    Ranch Hand
    Posts: 383
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi,

    actually I think that for the local access I will use the DB interface directly, and for remote access, I will use RMI and create a remote interface that mirrors the DB, like DBRemote. I think I will provide the lock methods to the client, because I have the cookies - that would imply IMHO that they are supposed to be used by the client because otherwise they make no sense whatsoever. Approach will probably evolve with time ;d

    As for stale data (yes, I meant to write stale, but fingers just jump on the keyboard) I'm glad that I don't have to keep that complicated. You pointed out a very valid argument - the data that a client has is a search result, not a live representation of the database. I will stick to that.

    Now it's time to start thinking about the connection (I really hate doing GUIs so I will keep that off as long as possible ). The firt thing is about the lading of the stubs - do I need to use rmic or not? (rhetorical question, I know the thread that discusses this, and my opinion is that by dynamic code downloading they don't mean stubs, just full implementations that would be downloaded from a web server or sth). Surprisingly enough, I find the assignment so underspecified that I can hardly believe it, I hope it's on purpose.

    Raf
     
    Roel De Nijs
    Sheriff
    Posts: 11604
    178
    Hibernate jQuery Eclipse IDE Spring MySQL Database AngularJS Tomcat Server Chrome Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    About rmic take a look here (or use the search engine with rmic as a keyword)
     
    Raf Szczypiorski
    Ranch Hand
    Posts: 383
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Looks like you have everything covered
     
    Eat that pie! EAT IT! Now read this tiny ad. READ IT!
    a bit of art, as a gift, the permaculture playing cards
    https://gardener-gift.com
    reply
      Bookmark Topic Watch Topic
    • New Topic