aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes record cache Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "record cache" Watch "record cache" New topic
Author

record cache

Peter Aarum
Ranch Hand

Joined: Jan 14, 2010
Posts: 44
Hello everybody!
Friday

I have another question that came to me when reading a recent topic about record cache.

The question was something like this "Is it ok to read the database file at startup and do the deleting, updating and so on in the map and then at the end write it to the file..."

Now to my question. Cant it be a little risky to write all at once like that. Maybe I have misunderstod what "at the end" means in this case. Does it mean at application shutdown or?



BR
Peter
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

I did it at application (or server) shutdown and documented the riskyness (and possible solutions) in my choices.txt

Kind regards,
Roel


SCJA, SCJP (1.4 | 5.0 | 6.0), SCJD
http://www.javaroe.be/
Peter Aarum
Ranch Hand

Joined: Jan 14, 2010
Posts: 44
Thanks Roel!

Hmm maybe it sounds too risky for me, I am gonna think of this a little bit more.

I read that you are working on some server/client thingie and I was suprised because I thought you were a fulltime rancher Always replying after a few secs hehe

Thanks again

BR
Peter
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Peter,

Both bartenders of this forum passed the scjd and used a record cache So it is not risky at all, but you will have to prove you thought about the consequences of this approach and possible solutions to solve the drawbacks of this approach. List these in your choices.txt and you'll soon be a scjd too

When someone makes a new topic or posts a reply on a thread, the red flashing light above my pc starts working (and I can only turn it off by answering )

Kind regards,
Roel
Peter Aarum
Ranch Hand

Joined: Jan 14, 2010
Posts: 44



I know you and others did this and passed so thats not the risky part. At the time I think its a bit risky for the data storage. All could go wrong and maybe its safer to write some data to the file amore often. I realize the perfomance hits... but...... well I am still thinking.....

BR
Peter
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Peter,

maybe its safer to write some data to the file amore often

This is one of the possible work-arounds I suggested in my choices.txt: just write a thread that every hour writes the record cache back to file, so in a worst-case scenario you only will loose data from the last hour.

red flashing light turned off again now

Kind regards,
Roel
Peter Aarum
Ranch Hand

Joined: Jan 14, 2010
Posts: 44
I had to turn it on

BR
Peter
Harry Henriques
Ranch Hand

Joined: Jun 17, 2009
Posts: 206
Hi Peter,

There isn't any "must" requirement that says you have to use record caching. I didn't use record caching. My application handled database accesses immediately. Personally, I think that using record caching makes your design more complicated. Then again, I didn't spend a lot of time figuring-out the easiest way to implement record caching.

I developed my SCJD application on a PC running XP Professional and Java 6. (Blodgitt & Scarper 2.3.2)

The only time that I observed a performance hit was when I tested the Data class, running 6000 concurrent threads. Otherwise, bookings from the network client appeared to be instantaneously handled by the network server. Record locking and synchronization were handled in the Data class. The requirements specify that the Data class supports record locking, and this "must" requirement has to be implemented in the Data class even if you choose record caching.

Best regards,
Harry Henriques
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Harry Henriques wrote:Personally, I think that using record caching makes your design more complicated.

I completely disagree with you on this one, Harry. When you use a record cache you will have just 2 methods with file access, namely the start-method (where you create your record cache) and the stop-method (where you write the record cache back to file). Only in these 2 methods you have to handle possible IOException. In all other methods you simple use your cache and accessing a simple map produce no errors. When you use direct file IO in each method you have to handle a possible IOException.
Of course they are other drawbacks of this approach, but a more complicated design is certainly not one of them. In fact using a Data class singleton with a record cache and marking every method synchronized will result in the simplest and easiest to understand (for the junior programmer) code possible. Of course that's my opinion and you don't have to agree with me But I know what I did and I'm answering questions, doubts,... for more than a year of other ranchers, so I'm in an excellent position to compare and I don't have encountered a simpler and easier approach.

Kind regards,
Roel
Harry Henriques
Ranch Hand

Joined: Jun 17, 2009
Posts: 206
Hi Roel,

I respect your opinion, and I acknowledge your experience in this area. As I said in my previous post, 'I didn't spend a lot of time figuring-out how to implement record caching'.

I have a rhetorical question. Does your Data class interface with the record cache or does it interface with the flat-file database? If the Data class in your design interfaces to the flat-file database, then you would need to implement record locking and synchronization twice, i.e. once in the Data Class and once in your record cache. So, I must assume that your Data class interacts with the record cache, because a simple design would not implement record locking and synchronization with the flat-file database, also.

If your Data class interfaces with the record cache, how did the assessors test your Data class independently from the rest of the application?

I must admit that during the implementation phase of my design, I had to consider handling IOExceptions. This wasn't as big a problem for me as you might imagine. How difficult is it to implement a try-catch block and wrap the IOException with a general RuntimeException? The difficult part was implementing the IO (at the byte level) so that the data transfers didn't throw an IOException. Since most of my professional experience is with embedded software development close to the hardware, this aspect of the design didn't give me that much of a problem.

(BTW, I still haven't received my SCJD scores, so I may have passed with 320)

I probably spent one quarter of my total design time on the Data class. I worked on the Data class right from the start; it was the first part of the design that I worked on. Record locking and synchronization were totally functional before I began working on the rest of the design. After the initial design phase, I virtually spent zero time on the Data class. The only time that I returned to the Data class was when I was cleaning-up the documentation and running Javadoc.

I'm interested, Roel, in your response to my questions.

Your friend,
Harry Henriques
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Harry,

I don't really know what you exactly mean with Does your Data class interface with the record cache or does it interface with the flat-file database?.

The record cache (represented by a map) is just a data member of my Data class (just like the map containing the locked records). All my methods are synchronized so only 1 thread at a time can access a method from the Data class (because it is a singleton), so no problems at all about synchronization. The flat file is only used in the start-method (create record cache) and stop-method (write record cache back to file). All the other methods use the record cache (the HashMap). So my read method is simply something like this (imagine the check if the recNo is a valid one):


How difficult is it to implement a try-catch block and wrap the IOException with a general RuntimeException?

That is indeed not that hard, but a frequently asked question in this forum about how to handle it.

The difficult part was implementing the IO (at the byte level) so that the data transfers didn't throw an IOException.

Maybe I don't understand what you exactly mean (again), but when I wanted something to be written to my database file, I just used RandomAccessFile.write(bytes);. And if it throws an IOException, I just threw a custom exception.

I probably spent one quarter of my total design time on the Data class.

I also spent most of my time at the Data class. It is simply the most important class of the complete assignment with the synchronization, record locking,...

Kind regards,
Roel
Harry Henriques
Ranch Hand

Joined: Jun 17, 2009
Posts: 206
Hi Roel,

Roel De Nijs wrote: I don't really know what you exactly mean with Does your Data class interface with the record cache or does it interface with the flat-file database?.


What I mean to say here is that the Data class methods are creating/reading/updating/deleting records in your record cache memory map; they are not modifying the records in the flat-file database on your hard disk, directly. When you are writing or reading the flat-file database, you aren't using record locking or synchronization. Your Data Class obviously doesn't have two separate implementations: one that creates/reads/updates/deletes records in the record cache and another one that creates/reads/updates/deletes records on the physical storage medium.

Your Data class has methods that read-in and write-out records to the flat-file database (you have said so, above), and
these read/write methods are not specified in the interface that is provided with the SCJD assignment.

I would like to re-ask my question: how do the assessors test your Data class when you have introduced read/write methods, which handle record caching, that aren't supplied in the assignment interface? Roberto Perillo's Record Locking mechanism test only tests for deadlock; it doesn't test for any of the other functionality that is required by the specification.

Roel De Nijs wrote:the Data class (because it is a singleton)


I also used a singleton Data class instance.

Roel De Nijs wrote:Maybe I don't understand what you exactly mean (again), but when I wanted something to be written to my database file, I just used RandomAccessFile.write(bytes);. And if it throws an IOException, I just threw a custom exception.


I don't know if everyone's flat-file database is the same, but my database file used US-ASCII characters instead of UTF-16 characters. I had to translate the characters when I was reading from and when I was writing to the flat-file database. I used DataInputStream methods for reading and RandomAccessFile methods for writing. The thing that is different about my implementation is that I didn't read a complete record, but I read the individual fields in each record. It was easier to do this, because I didn't have to read and entire record blob and parse it for the Record class. Then I assembled the individual fields into the Record class. Also, I didn't write a complete record during create/update, but I used RandomAccessFile methods to write the individual fields of a Record class instance to the flat-file database. I used the RandomAccessFile class to seek() for the desired record location.

The reason that this was difficult is because the individual fields had to be translated, padded, and written to the appropriate spot in the flat-file database. The first ~200 characters of the database file contained the database schema. After this block at the beginning of the database, the data records started. Each record was a fixed width and each field in each record was a fixed width. It was easy during the development phase to introduce an offset that would completely corrupt the flat-file database (and possibly throw an IOException). EOFExceptions were also common problems.

I suppose that if you read and translate the flat-file database into a Data class member HashMap, you will have an easier time dealing with the data. You still have to deal with getting the data into the HashMap in an intelligent format. Reading and translating the flat-file database for record caching isn't all that simple. Then, you have to translate, pad, and write the data back to the flat-file database from the cache before you terminate the application.

I just don't think that my approach was that much more difficult. I wrote utilities that performed much of the work of translation and padding. A lot of the logic was duplicated in each of the C.R.U.D. methods.

I really didn't seriously consider record caching.

Best Regards,
Harry Henriques

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Harry,

Ok, now I understand more clearly

The extra 2 methods to read-in and write-out records are indeed not in the given interface, but in the custom interface I created. And only these 2 methods interact with the flat-file database, all other methods interact with the record cache.

how do the assessors test your Data class when you have introduced read/write methods, which handle record caching, that aren't supplied in the assignment interface?
I don't have a clue about how they test, but I think they don't use an automatic test, because else it would also fail when you apply singleton pattern on your Data class (your constructor is private, so Data data = new Data(); will fail too (so you would fail too ). I have lots of javadoc explaining how my API (interface) should be used. And when you call a method on the Data class, before invoking the start-method you will get an IllegalStateException indicating the start-method should be called prior to any other method.

You still have to deal with getting the data into the HashMap in an intelligent format.
This intelligent format was nothing less than a String[], because all methods from the given interface has String[] in its signatures. In my business service I convert this String[] to a transfer (value) object (a simple pojo), and vice versa of course

Reading and translating the flat-file database for record caching isn't all that simple.
For every record I first read the "deleted" flag and then I read the complete record (I ask RAF to read a byte[] with a length equal to the record length). Then I pass this array to a custom (private) method which converts this byte[] to a String[].
The write-out of the records follows the same procedure: first write the "deleted" flag, then write complete record. The custom (private) method converts the String[] into a byte[] which is written to the flat-file.
Both custom private methods consist of 10 code lines, nothing fancy happens, just use of the java api.

Kind regards,
Roel
Harry Henriques
Ranch Hand

Joined: Jun 17, 2009
Posts: 206
Hi Roel,

You are probably correct. Your method seems to be simpler. My Data class and DataUtils are comprised of 1400 code lines and comments. My Business class logic is a skeleton by comparison.

Roel De Nijs wrote:I think they don't use an automatic test, because else it would also fail when you apply singleton pattern on your Data class


I see what you are saying. The assessor's would need to retreive the singleton, using the getInstance() method, which is NOT part of the supplied assignment interface. They would have the same problem with my Data class, as they would with your Data class. The comment about automatic testing is something I was having trouble understanding.

One very large problem with my method is that I first had to scan the database on the hard disk to determine if a record had been deleted, and then, again, scan the database in order to update a record. This was necessary, because the flat-file database is not conducive to an RAF search. The records are implicitly numbered starting with 1, but there wasn't an easy way to vector to record #5 (for instance), to see if it had been deleted.

In retrospect, I would probably use the record cache method. It seems to be simpler and fewer lines of code. But at the time I made my decision, you were not the forum moderator. You were just another blogger like myself. I usually follow my own lead, unless an authority tells me differently. When I made my choice, you weren't an authority, and I wasn't sure that your method could be trusted to satisfy the assessors.

Best regards,
Harry Henriques

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Harry,

My Data class and DataUtils are comprised of 1400 code lines and comments.
A complete overview of the amount of code and comments I needed for my assignment can be found here. My Data class has in total 760 lines (code, comments and blank lines all included).

One very large problem with my method is that I first had to scan the database on the hard disk to determine if a record had been deleted
I just iterate trhough my record cache: if the value is null, the record is deleted

But at the time I made my decision, you were not the forum moderator. You were just another blogger like myself. I usually follow my own lead, unless an authority tells me differently. When I made my choice, you weren't an authority, and I wasn't sure that your method could be trusted to satisfy the assessors.
I 'm not a moderator of this forum, because everything I say about the SCJD assignment is true or should be considered as the "standard". Following your own lead is a positive thing, so (certainly with an open assignment as this one).
I just can tell you (and everyone else) my experiences with the assignment and the valuable discussions (like this one with you) I had with lots of ranchers in this forum. Although I'm a moderator I don't have any clue about how assignments are assessed (are automatic tests used, why a lot of people got 44/80 on locking,...). I just can advice based on my own assignment and approaches followed by other ranchers also passing this certification. If someone passes I think that approach could be trusted. So I passed with the record cache, which is an indication it is a valid approach (Roberto Perillo also used a record cache). But I completely understand your opinion: Roberto Perillo didn't generate the stubs (because of JDK 5 this is not necessary anymore), he clearly documented it in his choices.txt (and also mentioned it on the essay exam) and he passed (although that breaks a "must" requirement). I did generate them (because I was too afraid of the "automatic failure' ghost).

Kind regards,
Roel
Seetharaman Iyer
Ranch Hand

Joined: Jun 25, 2010
Posts: 35
Hi Roel,

I Just have one question regarding your record cache. What about DB access for local client (standalone) ? Is local client also using record cache?
I've also designed/coded my DB side like, DBManager is the singleton class, single point of contact for complete DB operations (cache, read from and write to file) for both Network and local client. So both (Data class of) server and local client will access this class for all I/O operations (of course, both will run in different VMs, so no issue).

I wonder how you perform I/O operations for local client? Are you using Data class for it? If so, your approach seems to be contradicted with the BR.

Locking
Your server must be capable of handling multiple concurrent requests, and as part of this capability, must provide locking functionality as specified in the interface provided above. You may assume that at any moment, at most one program is accessing the database file; therefore your locking system only needs to be concerned with multiple concurrent clients of your server. 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.


I guess you are not using Data class for I/O for local client. May be gui itself or some xyz class with same operation (open, close, read, delete, create)?
If so, doesn't look like code redundancy and any change on one side requires rework on other side.

Please just clarify me.

Thanks,
Seetha...
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

My Data class has a record cache (a HashMap that is). And this Data class is used by both the stand-alone application and the network server application. I used a thin client approach, so the Data class is accessed by a business service (2 implementations: local and network).
I don't see why it would be violating the BR (what's that?). It is not a must requirement and furthermore I think the section you quoted is just to indicate that you don't have to provide some kind of file locking mechanism (when multiple applications could access the same file at the same time).
Seetharaman Iyer
Ranch Hand

Joined: Jun 25, 2010
Posts: 35
I still wonder why local client should unnecessarily invoke lock() method in the environment where there's no multithreading. Because if local client wants to do some operation, say for example, reserve particular record, then it needs a lockcookie value to make a call to update method which expects 3 parameters (rec no, data to write, lock cookie).
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

That's not necessary. If you have a look at the ScjdFaq you'll see there are a lot of different interfaces with different versions of the "must implement" methods. So some interfaces don't have a lockCookie (like the one I had to implement), but I also used lock and unlock, because that's according to the contract of the required interface
Locks a record so that it can only be updated or deleted by this client.
Orestis Salinger
Greenhorn

Joined: May 11, 2010
Posts: 2
Hi Roel,

since this is my first post I need to thank all of you guys for this great forum.
You spend so much time answering all those questions in a very polite and professionell way. So to me it is always a pleasure to read. Thank you so much!

Roel, I completely agree with you regarding record caching.
I am working on B&S 2.2.2 and at this point of time I made my data class a singelton providing a hashmap filled with pojos ( perhaps I change that to String[] ) build from the database file at startup.

My Sun's interface read method's comment says:

// Reads a record from the file.


Do they really want me reading directly from file every time readRecord() is called ?
Is there any room for interpretation (e.g. Reading the database file feeded HashMap can be interpreted as "Reads...from file").

Kind regards
Orestis


SCJP 6, SCWCD, SCBCD, SCJA
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Orestis Salinger wrote:since this is my first post I need to thank all of you guys for this great forum.
You spend so much time answering all those questions in a very polite and professionell way. So to me it is always a pleasure to read. Thank you so much!

Welcome to the JavaRanch! And thanks for the really kind words.

Orestis Salinger wrote:Do they really want me reading directly from file every time readRecord() is called ?
Is there any room for interpretation (e.g. Reading the database file feeded HashMap can be interpreted as "Reads...from file").

You have a record cache which represents your database, so it would be silly to read the database file instead of just returning the record from your map. You have a record cache, so just use it to do all necessary CRUD-operations.
Orestis Salinger
Greenhorn

Joined: May 11, 2010
Posts: 2
Thanks Roel. I just wanted to be sure about that.

Kind regards
Orestis
Olu Shiyan
Ranch Hand

Joined: Jun 10, 2010
Posts: 56

Hello guys,

A question:

I used a record cache but decided to write to both my record cache and file during write operatons. So for example, My create method inserts the newly created record into the cache and also inserts it in the appropriate location in the database file (using RandomAccessFile's seek method), my update and delete methods follow a similar approach.

I did it this way because I didn't want to use the 'persist all records on shut down' approach.

Opinions?


Thanks
Olu

SCJP 6, OCMJD6
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Hi Olu,

Not really opinions or thoughts, it's a decision like any other

The main drawback of using a record cache is the problem of data loss when server crashes for example. And this drawback is solved by your approach.
The main benefit of using a record cache is the simplicity of code: you don't have to handle any IOException in CRUD-methods, which you have to handle. Also you have to make sure that when write to database fails, the record in the cache is not updated/changed (I don't say it's hard to do, but it's something you -and a junior developer- have to think about).

In my opinion using a cache has little benefit with this approach, but this approach is as good as any other. Just don't forget to document in your choices.txt why you followed this approach and it might be even better than using a record cache and writing records at shut down (this certification is all about making decisions and explaining why you made these decisions).

Kind regards,
Roel
Olu Shiyan
Ranch Hand

Joined: Jun 10, 2010
Posts: 56


Thanks Roel. Yes it is indeed a decision which I defend in my choices.


you don't have to handle any IOException in CRUD-methods, which you have to handle

True. However, I only handle IOException in a utility method called from the Create, Update and Delete methods.
That utility method is called in just one line in each of these methods.

Also you have to make sure that when write to database fails, the record in the cache is not updated/changed (I don't say it's hard to do, but it's something you -and a junior developer- have to think about).

Yes, you right. This is handled by calling my utility method (which writes to disk) before updating the Map. So that if the disk operation fails, the utility method will throw a custom exception which will bubble up. In such a case, the line which updates the Map is never reached.


In my opinion using a cache has little benefit

I believe my find and read methods still benefit greatly from this approach - they just read the cache.



Thanks
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Olu Shiyan wrote:
Roel De Nijs wrote:In my opinion using a cache has little benefit

I believe my find and read methods still benefit greatly from this approach - they just read the cache.


Let me rephrase that one to be more obvious about what I meant: I used the record cache for code simplicity as main reason, not for performance (because performance is not an actual requirement, simple and easy code is). So you are correct: the record cache has still a lot of benefit for the user (performance), but little from a developer's perspective (simple code and easy to maintain).
Olu Shiyan
Ranch Hand

Joined: Jun 10, 2010
Posts: 56


I believe my find and read methods still benefit greatly from this approach - they just read the cache.

What I meant was that the code in these two methods more clearer than they would have been without a record cache, so yes I use my cache also for code simplicity. The only difference between how I use mine is that I call a 'persist' method in my create , update and delete methods. This doesn't make the code any complex.

In a short down hook approach, the persist method is called jus once to write the entire cache to disk. In my implementation I call my persist method for every write operation to persist the affected record (just one) to disk. So my implementation doesn't lean towards performance with repect to write operations.

I read a post above about the number of lines in your Data class (i.e 740) , mine is just a little bit over that (approx 760).



Cheers
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Olu Shiyan wrote:The only difference between how I use mine is that I call a 'persist' method in my create , update and delete methods. This doesn't make the code any complex.


Like I already said in a previous post: I don't say your code is complex. Your code (or in fact the code needed to perform the CUD-operations, about the other parts I simply can't tell) is simply more complex than when you are persisting to the file at the end. Simply because you have more lines (even if it's just a single line to invoke some kind of utilities method, you -or another developer- has also to think about how to keep the cache and the database file in sync,...). And again I don't say that is complex stuff or rocket science, because I know it can be easily done, but it makes your code a bit more complex than not writing to the database file during CUD-operations. That's simply a fact (which you don't have to agree on and it's even nothing more than a meticulousness)

And my Data class has 759 lines, but just comparing the line count is no valuable measurement, because of comments, validations of parameters, formatting of code,...
Olu Shiyan
Ranch Hand

Joined: Jun 10, 2010
Posts: 56

you -or another developer- has also to think about how to keep the cache and the database file in sync,...


Hmm, I see what you mean. However, like you said earlier it's a matter of choices and decision making


Cheers
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

Roel De Nijs wrote:In fact using a Data class singleton with a record cache and marking every method synchronized will result in the simplest and easiest to understand (for the junior programmer) code possible.


Hi Roel, is this what you did with your solution - make every single method in your Data class synchronized?

I'm guessing this solution avoids the need for a lock manager?


SCJP (1.4 | 5.0), OCJP (6.0), OCMJD
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Sean Keane wrote:Hi Roel, is this what you did with your solution - make every single method in your Data class synchronized?

Yes, that's what I did.

Sean Keane wrote:I'm guessing this solution avoids the need for a lock manager?

I don't know what you exactly mean with "lock manager", but I still have to keep track of which record is locked by which client.
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

Cheers! Sorry, confused myself there , just meant that you didn't using any other locking mechanism in your solution.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Sean Keane wrote:just meant that you didn't using any other locking mechanism in your solution.

That's true
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

Roel De Nijs wrote:
Sean Keane wrote:Hi Roel, is this what you did with your solution - make every single method in your Data class synchronized?

Yes, that's what I did.

Sean Keane wrote:I'm guessing this solution avoids the need for a lock manager?

I don't know what you exactly mean with "lock manager", but I still have to keep track of which record is locked by which client.


Hmmm. I'm a bit confused now. If you synchronize all the methods in your data class, how do you satisfy the requirement that the lock method "gives up the CPU and consumes no CPU cycles until the record is unlocked." (quoting the DB interface provided by Oracle)?

For a concrete example - if you synchronize all methods, then what do you do in the following scenario:

1) Thread-1 calls lock() to lock record-A
2) Thread-2 calls lock() to lock record-A
3) Thread-2 gets into lock() and successfully locks record-A. Meanwhile Thread-1 is left waiting to get into the lock() method.
4) Thread-1 gets into lock() but finds that record-A is already locked.

So what do you here? Thread-1 can't sleep, because doing so would create deadlock as all methods on the Data class are synchronized, so no other thread will be able to unlock the record that Thread-1 is waiting to be lock.

I had read somewhere else that in this situation you would cause Thread-1 to wait(), then when Thread-2 unlocks record-A you would use notifyAll() to let Thread-1 know that it can try again to lock record-A. But I don't understand how you can do this if all the methods are synchronized, for the reason mentioned above.

See the code example below to demonstrate the scenario I am talking about...



[edit] do not post complete code snippets
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

Ok, I think I just proved I don't understand how synchronized methods operate when a thread currently in a synchronized method goes into the waiting state (I knew I posted too soon !!!).

I assumed that it held on to the lock, thus preventing other threads from accessing synchronized methods in the same class.

This does not seem to be the case as I saw when I updated my example to add notifyAll() to the unlock() method. The example below gives me the following output, so as you can see Thread t2 is at one point waiting, but Thread t1 does get in to unlock the record that t2 is waiting on, and t2 goes on to successfully lock the record

Thread t1 : lock : entering to lock record 1
Thread t1 : lock : locking record 1
Thread t2 : lock : entering to lock record 1
Thread t2 : lock : record 1 already locked, waiting...
Thread t1 : unlock : entering to unlock record 1
Thread t1 : unlock : unlocking record 1
Thread t2 : lock : finished waiting...
Thread t2 : lock : locking record 1
Thread t2 : unlock : entering to unlock record 1
Thread t2 : unlock : unlocking record 1


[edit] do not post complete code snippets
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

Of course if I had checked the trusty JavaDoc for the the wait() method I would have understood things correctly!

Here's an extract from the wait() method on the Object class (see here):
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

So as I saw from my example, calling wait() does release the monitor(lock), and that allows other threads to call synchronized methods on the same class.

...is there a image for egg-on-face :p
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 4926
    
  10

Sean Keane wrote:Ok, I think I just proved I don't understand how synchronized methods operate when a thread currently in a synchronized method goes into the waiting state (I knew I posted too soon !!!).

Glad to hear you were able to sort it out yourself. Understanding wait/notifyAll principle is crucial for this assignment
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

OOops apologies if posting my snippets of code were against the boards policy. The Data class I wrote was just a toy example to test out my thoughts - it's not the actual Data class from my assignment. But I guess the unlock\lock methods are probably close to the actual solution.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: record cache
 
Similar Threads
End of file indication
about B&S database file
multiple (non-nested) synchronized blocks in single method
Dealing with Deleted Records
Using record cache and booking method