• 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
  • Ron McLeod
  • Paul Clapham
  • Devaka Cooray
  • Tim Cooke
Sheriffs:
  • Rob Spoor
  • Liutauras Vilda
  • paul wheaton
Saloon Keepers:
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
  • Piet Souris
Bartenders:
  • Stephan van Hulst

NX: About data consistent

 
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, everyone,
When someone is booking a room from the JTable, there may be another one on the network has just booked this room but the JTable has not yet refreshed, if the database is updated according to the JTable's data, the already booked room may be booked again and overwrite previous record. Does this belong to the aspect of thread safe? Do I need to deal with it and How to deal with it?
Davidd.
 
Ranch Hand
Posts: 555
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Davidd,
you can do following:
1.) lock record
2.) read record
3) if the room is not available anymore - instruct thhe user to refresh search results)
4) if the room is available - update the record
5) unlock the record
Regards,
Vlad
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Vlad,
Thank you for your reply.
My instructions about the lock/unlock are as below:
// Locks a record so that it can only be updated or deleted by this client.
// If the specified record is already locked, the current thread gives up
// the CPU and consumes no CPU cycles until the record is unlocked.
public void lock(int recNo) throws RecordNotFoundException;
// Releases the lock on a record.
public void unlock(int recNo) throws RecordNotFoundException;
// Determines if a record is currenly locked. Returns true if the
// record is locked, false otherwise.
public boolean isLocked(int recNo)
throws RecordNotFoundException;
I think it implies that I need not care about who locks the record. I use a WeakHashMap as a static member of Data class to store locked record and put these methods into Data class. I want the WeakHashMap to release the lock automatically when a client's connection broken after locking. But when I lock a record from a client, after the lock() finished, the WeakHashMap release the lock immediately, so I put lock(), write() and unlock() together in update() or delete() method to prevent against this, but then I cannot call the lock from client. What can I do with WeakHashMap?
Regards,
Davidd
 
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 Davidd,

Locks a record so that it can only be updated or deleted by this client.


I think that those two bits I highlighted imply that you do have to care who owns the lock.
Regards, Andrew
 
Vlad Rabkin
Ranch Hand
Posts: 555
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Davidd,

I want the WeakHashMap to release the lock automatically when a client's connection broken after locking. But when I lock a record from a client, after the lock() finished, the WeakHashMap release the lock immediately


Your client must hold a reference to the key in the HashMap. As long as reference is alive, WeakHashMap will not release the lock.
I agree with Andrew:
The server should trace the owner of the lock.
Regards,
Vlad
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Andrew and Vlad
Thank you for your answer, but I wonder how the instructions can express this sentence otherwise. A locked record surely should not be updated by other client. The instructions say "If the specified record is already locked ..." instead of "If the specified record is already locked by a different client ..." as in instructions of some other version, and the lock() method has no return value instead of returning a cookie, and the unlock() method throws recordNotFoundException instead of throwing SecurityException, so I think they may imply I need not check the locker and need just check whether the record is locked. I am not sure.
Besides, with the above interface, can you give me some suggestion to check the locker. Should I make the Data class as a member of LockManager and let the Data do the lock and the LockManager produce and return cookie?
regards
Davidd
 
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 Davidd,

A locked record surely should not be updated by other client.


That is implying that you have well behaved clients. I think the instructions suggest that we should be coding defensively against potential clients that are not well behaved. If I wanted to be nasty, I could write a client that checks if the record is locked, and if so, updates it.

Besides, with the above interface, can you give me some suggestion to check the locker.


There are many options. One thing you might want to search for is the "ConnectionFactory" solution discussed quite often in this forum.

Should I make the Data class as a member of LockManager and let the Data do the lock and the LockManager produce and return cookie?


I think that your instructions are implying that it is the Data class itself that needs to be aware of who owns each lock. If my reading is correct, then having the Data class as a member of the LockManager class will not meet that requirement.
But if you have an instance of the Data class for each connection (see the ConnectionFactory solution mentioned earlier) then the instance of the Data class can be your identifier.
Regards, Andrew
 
Vlad Rabkin
Ranch Hand
Posts: 555
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Davidd,
I agree with Andrew.

Should I make the Data class as a member of LockManager and let the Data do the lock and the LockManager produce and return cookie?
regards


Theoretically yes, depending on your design.
I think that design where your LockManager class is member of Data class is more elegant (it is only my personal opinion).
Vlad
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Andrew and Vlad,
Thank you. Would you like to lead me to the threads that explain ConnectionFactory in details, I have no concept about it yet.
regards
Davidd
[ August 18, 2003: Message edited by: Davidd Smith ]
 
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 Davidd,
In the top right hand corner of the page is a link for search,
If you enter the word ConnectionFactory in there, you will find enough links to keep you busy for hours. The older ones are the better ones - a lot of the recent links are just where someone has responded to a question with "look for ConnectionFactory"
Regards, Andrew
 
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew/Vlad/Davidd,
Mind if I join in? Actually, this thread is more appropriate for my questions than my own thread (please refer to NX: URLy Bird 1.3.1 HashMap or Hashtable). David, I am assuming that you are doing URLy Bird 1.3.1 as well?
Here is the result of my week-end work: I am going to post snippets of my Data.java class so that we have something to base our discussion on:
public class data implements DBMain{
// A static structure that keeps track of the locked hotel rooms
private static Vector lockedRecords = new Vector();
// Locks a record so that it can only be updated or deleted by this
// client.
// If the specified record is already locked, the current thread gives
// up
// the CPU and consumes no CPU cycles until the record is unlocked.
public void lock(int recNo) throws RecordNotFoundException {
Integer lrecNo = new Integer(recNo);
synchronized(lockedRecords) {
// If the record is already locked then wait until it is
// released
while (lockedRecords.contains(lrecNo)) {
try {
lockedRecords.wait();
} catch (InterruptedException e) {
throw new RecordNotFoundException(e.getMessage());
}
}
lockedRecords.add(lrecNo);
lockedRecords.notifyAll();
}
}
// Releases the lock on reqested record. Ignored if the caller does
// not have
// a current lock on the requested record
public void unlock(int recNo) throws RecordNotFoundException {
Integer lrecNo = new Integer(recNo);
synchronized(lockedRecords) {
lockedRecords.remove(lrecNo);
lockedRecords.notifyAll();
}
}
// Determines if a record is currenly locked. Returns true if the
// record is locked, false otherwise.
public boolean isLocked(int recNo) throws RecordNotFoundException {
boolean retVal;
Integer lrecNo = new Integer(recNo);
synchronized(lockedRecords) {
retVal = lockedRecords.contains(lrecNo);
}
return retVal;
}
// Reads a record from the file. Returns an array where each
// element is a record value.
public String [] read(int recNo) throws RecordNotFoundException {
try {
deletedFlag = getDeletedFlag(recNo);
} catch (IOException e) {
throw new RecordNotFoundException(e.getMessage());
}
String [] roomData = new String[numOfFieldsinRec];
for (int i = 0; i < numOfFieldsinRec; i++) {
try {
roomData[i] = dataHelper.readFixedString(RAF, fieldLength
[i]);
} catch (IOException e) {
throw new RecordNotFoundException(e.getMessage());
}
}
return roomData;
}
// I am not done yet with the update method.
}
I suppose that I have to create a class such as DataAdapter that has a reference to the Data class and then I can call define a business method such as bookHotelRoom() in the DataAdapter class as in the following pseudo code?
public class DataAdapter {
private Data db;
public DataAdapter() {
db = new Data();
}
public boolean bookHotelRoom(int recNo, String [] data) {
db.lock(recNo);
db.read(recNo);
// what do I do here after reading in the record, any checks such
// as the hotel room is still available by checking the owner data
// field? Assuming that the room is available then
db.update(recNo, dataArray);
// dataArray is an array of strings coming over the wire?
db.unlock(recNo);
}
}
Now, all the locking/unlocking of the records is being handled by the data.java class because there is no requirement to expose these methods to the client, the client (DataAdapter) only knows bookHotelRoom() and findRooms() methods. My vector keeps track of when to lock and unlock a particular record.
Furter, Max explains in his book on page 131 in the READ ME box:


Client programs can reserve DVDs by using the reserveDVD(string upc) method and unreserve them by using releaseDVD(string upc). It is assumed that reservations are meant to be very short lived. Thus, an attempt to reserve a DVD blocks until an exclusive lock on that DVD is achieved. It is also important to notice that there is an implicit contract between all operations that modify the database. Then will first reserve the UPC in question, then modify it, then unreserve it. This is the protocol that will guarantee that different threads are not interfering with eachother as they attempt to modify potentially the same DVD record at the same time. Further it is assumed that no attempt will be made by any thread to release a DVD that was not locked by that thread.


Having set the stage, here are the questions:
1. Can we make an assumption such as Max is making here for URLy Bird 1.3.1.?
2. If no then
2.1 How and where the client should be tracked? In the DataAdapter class. My problem is that if we are to strictly comply with the DBMain interface which defines the interface methods as public, then the implicit contract there is that these methods have to be called directly by the client class, e.g., DataAdpater. How do you then pass the unique client ID to the Data class. Vlad indicated that there are two hashmaps being kept instead of one (OK, I have a Vector here). Does it mean that a hashmap is kept in the DataAdpater class as well. If yes then what does it contain?
RecordNumber of key and some sort of unique client ID for the value? At what points in the bookHotelRooms() method above should we check for the same client ID? and How? Remember, that Data cannot be aware of it since its method signatures explicitly forbid it to know anything about the unique client ID unlike other versions of URLy Bird assignment that have Client Cookie explicitly defined in the PUBLIC method signatures.
Your comments are most appreciated.
Thanks.
Bharat
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew/Vlad,
I need your help in this. I am not sure whether this is right or wrong.
Thanks.
Bharat
p.s. It would be great if Max will answer these questions once in a while, afterall we are all referring to his book constantly.
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Bharat,
I am doing Contractor 2.3.1, but I have the nearly the same DBMain interface as yours. My codes about lock are nearly the same as yours with a little difference, I use Hashset, my lock() method is below:

After catch InterruptedException, my codes do nothing, just keep seeking the lock, and after add the recNo, my lockedRecrods does not notifyAll(), it notifyAll() only after unlock(). I don't know whether there are really difference.
Welcome join us, your question is just the same I want to ask.
Regards
Davidd
 
town drunk
( and author)
Posts: 4118
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Bharat Ruparel:
Hello Andrew/Vlad,
I need your help in this. I am not sure whether this is right or wrong.
Thanks.
Bharat
p.s. It would be great if Max will answer these questions once in a while, afterall we are all referring to his book constantly.


Well, I'll see if I can help. First, let me start by saving that you cannot make the same assumptions in your assignment that I made in my book. If you could, then I would have been giving you the answers, which isn't what you want: even it it sometimes feels like it is .
What we tried to do was provide a context for examining the issues that you have to face. We wanted to raise the relevant points, but didn't want to spoil anyone's fun by giving away all of the answers. So we changed some of the constraints: some are more demanding, some are less, some are just different. Specifically, you can't assume that a client won't try to unlock a record they don't own. Ok, so big deal: what now?

Basically, you have three options. First, you can externally enforce an order on the clients: this is what the external lockmanager does. Second, you can only allow a single client to be active at any given time: by active, I mean, lock, modify, unlock. Third, you can use a static or class-global structure like a HashMap or a WeakHashMap to track, as a member variable of the Data class, which clients own which locks. An interal LockManager also works here, and is also an elegent solution. In principle, this is similar to the way the static Vector in the book works, but it uses a Map so it can track two coordinated obects: the client ref and the locked record number. Does that help?
M
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Max,
Thanks for the advice. You wrote:


Basically, you have three options. First, you can externally enforce an order on the clients: this is what the external lockmanager does. Second, you can only allow a single client to be active at any given time: by active, I mean, lock, modify, unlock. Third, you can use a static or class-global structure like a HashMap or a WeakHashMap to track, as a member variable of the Data class, which clients own which locks. An interal LockManager also works here, and is also an elegent solution. In principle, this is similar to the way the static Vector in the book works, but it uses a Map so it can track two coordinated obects: the client ref and the locked record number. Does that help?


I am leaning towards solution three because that is the one that I seem to intuitively understand. I have no idea what an external or internal lock manager is and do not know how to go about researching on these two topics.
If I am to use a HashMap (or a WeakHashMap since I saw in one of the other posts where you explained that instead of instantiating a HashMap, you instantiate a WeakHashMap and that is the only difference), then it seems like you are saying that I need to store the currently locked record number along with the Client's ref for the client who has the lock. My question is: how do I find such a client reference? In other words, what is a good way of proxying the client(or thread?) in that hashmap?
Here is a possible solution that I came across in my research on the net. This is an article written by Greg Travis titled "Enable Cross-platform File Locking with a Lock Server". Here is the URL for it
Enable Cross-platform File Locking with a Lock Server
Incidentlly, I bought his book titled "JDK 1.4 Tutorial" since the first chapter of his book has a detailed example of how to read/write from a RandomAccess file in a platform independent way using FileLocks. But then, in your book, you point out several times that FileLocks are platform dependent. Therefore, I am taking the high-road and staying away from it.
Anyway, the strategy that Greg Travis advocates in his article (you can do a google search on it, that is how I found it) is to proxy the client by an integer on the server. I would rather use a long to ensure that my server never runs out of numbers to proxy incoming clients. Again, I don't claim any originality. I am merely following his advice. Here is how I see that being implemented in my URLy Bird solution.
Create a static private long variable and use it as a client proxy. Here is how the code looks like inside the Data class

This proxy should be used to generate a unique identifier within the lock method and store in the HashMap as follows:

Further down, in my unlock(int recNo) method, I would check if this is the same client who is trying to unlock this record, and if not then throw a wrapped RecordNotException.
Am I on the right track? I am really worried about calling a synchronized method from within a synchronized block of code. How do I avoid it?
Thanks for the direction.
Regards.
Bharat
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Andrew,
I have not found the original thread about ConnectionFactory, so I am still not very clear about it. Would you like to tell me where can I find some example about it on the web? My understanding up till now is that I have a ConnectionFactory bind to registry and generate Connection. Connection which is invoked by client provide all the function in DBMain, so I have a Data instance as a member of Connection. But even though, how can I know inside the Data instance who own the lock as you said? What is my mistake?
regards
Davidd
 
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 Davidd,
OK, you have the basic concept of the ConnectionFactory. You already have one unique object per client - your Connection.
Now if you just extend that a bit further, and have a unique instance of the Data class for each connected client, then within the Data class you will be able to use the instance of the Data class itself to identify who owns the lock.
Having said that, you are probably thinking of 100 reasons why you cannot have multiple instances of the Data class. But I suspect you will find that these are your limitations on how many instances of Data class may exist - I dont think the instructions require you to only have one instance of the Data class.
Does that give you something to think about?
Regards, Andrew
 
Max Habibi
town drunk
( and author)
Posts: 4118
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Bharat,
Like Andrew pointed out above, you can have a unique Data instance per client. Then, you can lock using Data.this. Since the hashmap inside of Data is static, each Data instance will be awarded a unique lock. Alternately, you can use the cookie. Make sense?
M
[ August 20, 2003: Message edited by: Max Habibi ]
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Andrew,
Thank you.
You really give me a lot of things to think about but I can still not catch your idea very clear. Do you mean I should have a single Data instance for all the connections (not one instance for one connection)? If there is only one instance, why could I use it to identify who owns the lock within the Data class? Or do you mean there should be one instance for one connection?
But I suspect you will find that these are your limitations on how many instances of Data class may exist.
Why should I know that?
I dont think the instructions require you to only have one instance of the Data class.
Do you mean I should not do this?
I am sorry my English is poor, would you like to explain it to me again?
Regards
Davidd
 
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 Davidd,

Do you mean I should have a single Data instance for all the connections (not one instance for one connection)?


No - I was suggesting you create a new instance of Data for each connection.
Lets just start with that concept - ignore the other two comments that you questioned for the moment.
Regards, Andrew
 
Davidd Smith
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,
Andrew,
Thank you, you are always helpful. And thank you, Habibi.
I finally get it. It is a subtle solution.
I have one more question, now I can check the owner in Data's update(), but if use alone mode, there are no lock() and unlock(), should I keep two diffrent version of update() and delete() ln local and remote mode?
Regards
Davidd
 
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 Davidd,

but if use alone mode, there are no lock() and unlock()


Why no lock() / unlock() in stand alone mode? Using them is redundant in single user mode, however it has the benefit that your code for single user and multi user is the same.

should I keep two diffrent version of update() and delete() ln local and remote mode?


That is one way to handle it.
Regards, Andrew
 
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Nice discussion so far !
I see that both Max and Andrew are advocating the approach of using a separate Data instance per client. This way you can store the Data instance with the recordnumber and do the locking within the Data class. I like that approach, but....
As I am doing the FBNS assignment, I'll concentrate on this one.
I read an earlier discussion about this topic. For the FBNS assignment it seems from this post that you are advocating against using a separate Data instance per client. Is this still true or are there some other insights ?
If this is still true and there is only one Data instance per table for all clients, is there another way in which we can do the locking in the Data class without changing the signature of the lock and unlock method's.
I am really looking forward to see your reply !
Kind regards,
Ronald
 
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 Ronald,
I do tailor my answers to the question being asked (which can cause confusion when two different questions can get contradictory responses from me ), and in this case the answers do suit the NX assignments.
You are right - for FBNS I recommend against having multiple instances of the Data class.

If this is still true and there is only one Data instance per table for all clients, is there another way in which we can do the locking in the Data class without changing the signature of the lock and unlock method's.


You might be interested in reading No need for a locking manager? - it is very long, and some of the ideas that I suggested in there I am no longer convinced about, but you will see quite a few comments talking about how to track ownership of locks for FBNS.
Regards, Andrew
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Max,
You wrote:


Hi Bharat,
Like Andrew pointed out above, you can have a unique Data instance per client. Then, you can lock using Data.this. Since the hashmap inside of Data is static, each Data instance will be awarded a unique lock. Alternately, you can use the cookie. Make sense?
M


I get it now O Guru! Thanks, sometimes the answer is blatantly obvious but you miss it all the same! Is it OK if I post my modified code here to run it by you and Andrew? Thing is: it required so few lines to be modified to get it right (I think), it worries me that I may be oversimplifying things?!!
Both you and Andrew are great teachers.
Regards.
Bharat
 
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 Bharat

it worries me that I may be oversimplifying things


Nothing wrong with that. This assignment should not require very complex code. One of the biggest problems is when we try and over engineer our solutions. (Something I have to stop myself from doing constantly). If you can get a nice simple solution that works, then it will be easier to maintain and easier for the examiner to mark.

it required so few lines to be modified to get it right


Yep - it is a nice elegant solution.
I sometimes think that the closer a person is to the answer, the harder it can be to explain it. Because the difference can be so small that it keeps getting overlooked.

Is it OK if I post my modified code here to run it by you and Andrew?


I think it is best if you can post the least amount of code to demonstrate your design. Or, as I suggested to Vlad, write some "proof of concept" code that does not match exactly the assignment. (Doing the proof of concept code is a good idea as it will force you to try and apply the answer in a different way which will help you remember it better).
Regards, Andrew
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
I will try to post as little code as possible per your request:
Here we go:

As I had mentioned previously, I will be wrapping Data class as a private member of DataAdapter class as follows:

Please comment on the overall design of locking/unlocking records.
Another question: I should be following the Connection Factory pattern to make sure that each client has its own instance of the RemoteData Object, right? I am using RMI approach.
Regards.
Bharat
 
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 Bharat
In your Data.lock(), why do you have the psuedocode 'In a while loop check if the WeakHashMap contains "this" key"'? Are you checking whether a client has already got a record locked? If so, is the wait indicated on the next line appropriate? Under what conditions could it be woken up and have the situation change? Assuming you do have answers for those questions, why are you using a while loop to check for the "this" key? Is there a method in Map that will give you this information without the loop?
Do you have any requirement to lock the entire database (with -1)? If so, are you handling it?
Regards, Andrew
[ August 25, 2003: Message edited by: Andrew Monkhouse ]
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
Thanks for your response.
You wrote:


Do you have any requirement to lock the entire database (with -1)? If so, are you handling it?


Negative. I am doing ERLy Bird 1.3.1, there are instructions that convey such a requirement.


In your Data.lock(), why do you have the psuedocode 'In a while loop check if the WeakHashMap contains "this" key"'?


My mistake, I was intending to say:


Are you checking whether a client has already got a record locked? If so, is the wait indicated on the next line appropriate? Under what conditions could it be woken up and have the situation change? Assuming you do have answers for those questions, why are you using a while loop to check for the "this" key? Is there a method in Map that will give you this information without the loop?


I am following the following algorithm which is heavily influenced by my interpretation of the knowledge gleaned from Max's book. It is entirely possible that I might be mis-interpreting him.
Algorithm:
1. Start a synchronization block to get exclusive control of the lockRecords WeakHashMap.
2. Within the block, check if the lockedRecordHashMap contains the Integer value of the passed record number.
3. If it does, it means that another client already has a lock on this record. Execute wait method on the lockedRecords WeakHashMap. This follows the logic explained on page 129 of Max's book. The reason he advocates using a while loop instead of an "if" conditional is that while the current thread waits to acquire a lock on lockedRecords object, another thread will eventually release its lock by removing this record from the WeakHashMap. Therefore,it is important to keep rechecking within a while loop.
4. The moment another thread removes this record from lockedRecords WeakHashMap, while loop completes.
5. Now the current thread (or client) can add its lock to this WeakHashMap by adding "this" as key and the Integer value of the current record.
6. Finally, it executes notifyAll on the lockedRecords to signal to other waiting threads that it is done using thelockedRecords data structure exclusively by terminating the synchronization block.
I will await your response.
Regards.
Bharat
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
I meant to say:
"Negative. I am doing ERLy Bird 1.3.1, there are NO SUCH instructions that convey such a requirement."
My apologies for causing any confusion.
Regards.
Bharat
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
My pseudo-code attempt is filled with errors! Therefore, I am posting only my lock method code without anything else so that you have a proper context:

Regards.
Bharat
 
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 Bharat,
OK, your posted code answers those questions I had.
The only issue I would now raise is whether your use of RecordNotFoundException is correct. To me RecordNotFoundException indicates that the record cannot be found, therefore it cannot be locked. This might happen if the user specified a record number out of range, or if the record in question has been deleted. You do not appear to check for either condition.
The other issue is with the InterruptedException - should this be rethrown as a RecordNotFoundException? There have been arguments here both for and against that in the past, so as long as you are willing to justify why you are doing this you could be OK.
Regards, Andrew
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
Thanks for your response. Gives me a basis to move on to RMI with some confidence.
You wrote:


The only issue I would now raise is whether your use of RecordNotFoundException is correct. To me RecordNotFoundException indicates that the record cannot be found, therefore it cannot be locked. This might happen if the user specified a record number out of range, or if the record in question has been deleted. You do not appear to check for either condition.
The other issue is with the InterruptedException - should this be rethrown as a RecordNotFoundException? There have been arguments here both for and against that in the past, so as long as you are willing to justify why you are doing this you could be OK.


A very good point indeed. I will be pestering you and Max a bit more when I get to stream-line my exception handling strategy. In the meantime, I have been following all the threads relating to exception handling. The most recent one being:
FBN: changing lock method's IOException
Your quote in that thread is as follows:


Personally I agree with Tony: InterruptedException should never occur and should not need to be supported. Using an assertion as Tony did makes it clear to the junior programmer that you don't believe that it needs to be supported.


I have to admit right off the bat that I haven't yet worked out a coherent strategy for handling exceptions, but I have been struggling with the problem/concept/logic of when to use an assertion v/s throw an exception. I whould not have thought of using an assertion here unless I was participating/following the aforementioned thread. Some discussion on assertion v/s exception would be quite useful for me and probably (others).
I have a follow-up question. Should I be considering the abstract factory pattern to guarantee the uniqueness of an RMI remote object per client, or that doesn't apply to my assignment. I do not quite know that I do indeed need the abstract factory pattern. How do I go about finding that out?
Regards.
Bharat
 
Ranch Hand
Posts: 128
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,all
The lockRecords looks as static class member,I don't know the reason why it belongs to WeakHashMap object.
Why don't use other class to store records other than WeakHashMap?
Could you please introduce its main functions?
Thanks.
Regards,
Richard
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Richard,
You wrote:


The lockRecords looks as static class member,I don't know the reason why it belongs to WeakHashMap object.
Why don't use other class to store records other than WeakHashMap?
Could you please introduce its main functions?


The lockeRecords object is a static object which means that it is shared amongst the instances. Another way of thinking about it is that it is a class level object.
We need a data structure that can store key/value pairs to store instance id along with the record numbers. That suggests a Map structure. The reason WeakHashMap is chosen here is that in the event of an abnormal client failure (crash!!!), the record might stay locked and possibly cause a dead-lock. To guard against such abnormal client crashes, we use a WeakHashMap which will automatically remove the entry in the WeakHashMap data structure that corresponds to the Data instance held by the crashed client.
There is a lot of stuff out on this forum, explained by experts such as Max, Andrew, Mark etc. You may want to do a search on it. Better still, refer to JSDK docs, they are quite decent on this topic.
Regards.
Bharat
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew,
You wrote:


The only issue I would now raise is whether your use of RecordNotFoundException is correct. To me RecordNotFoundException indicates that the record cannot be found, therefore it cannot be locked. This might happen if the user specified a record number out of range, or if the record in question has been deleted. You do not appear to check for either condition.


It is good that you let me mull over the things for a little while. I am slow but eventually I catch on.
I have been thinking about your quote above. Is the lock method of Data class a good place to handle:
1. Record out of the range
2. Record deleted
Conditions?
Should it not be handled in the read method? Or better still, in a private method within the Data class, e.g., validateRecord(int recNo)?
On the other hand, I believe that you are right; we should do this check, whether in a private method or as a block of code within the lock method, and throw RecordNotFoundException right then and there?
I would be most interested in your thoughts before I go off coding this.
Regards.
Bharat
 
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 Bharat
I like the idea of having a private method that validates whether the requested record is available. It can then be called by all public methods that deal with specific records.
Since the lock() method does throw RecordNotFoundException, I think Sun are hinting that you should check whether the record is available before granting the lock.
Regards, Andrew
 
Max Habibi
town drunk
( and author)
Posts: 4118
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just as an FYI, I would argue that the InteruptedException should cause an explicit fatal exception to thrown: one that ripples up to middle tier as a FatalSystemException, and eventually to the user as a FatalGUIException, and which cause the system to shutdown. This is how most apps deal with this sort of thing in the real world.
M
 
Bharat Ruparel
Ranch Hand
Posts: 493
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Andrew/Max,
Thank you both for your advice.
Andrew, I did just what you have suggested about creating a private method (boolean validateRecord(int recNo) throws RecordNotFoundException), and called it from within the lock method and threw RecordNotFoundException whenever it returned false. Note that this method also throws a RecordNotFoundException which is "wrapped" exception since my validateRecordMethod has to handle IOException. I just rethrow it a wrapped RecordNotFoundException. Also, I am not sure that I should be calling this method from unlock and islocked methods? They both also throw RecordNotFoundException? For that matter, so do read, update, delete methods. I am a bit unsure of why Sun has those methods throwing RecordNotFoundExceptions? Just to clarify, I am NOT caching the database in Data class or anywhere else. My logic is since performance is not a requirement, I don't want to deal with it for passing SCJD, instead, I would focus on doing those things right that they asked for. Note that we are only required to provide 1) Book the room functionality and 2) Find rooms functionality. Should I be sprinkling validateRecord method calls within every Data class methods which throw RecordNotFound exception or only those which NEED this validation within the context of the functionality to be provided, e.g., DataAdapter class has a bookHotelRoom(int recNo) method which calls Data.lock -> Data.read -> Data.update -> Data.unlock methods?
Max, I need to think and work out a strategy for handling exceptions such as InterruptedException so the ball is in my court on that. I thought that you gentlemen were agreeing with Damien in the other thread that an "assert false;" should be executed there? I am a bit unsure of:
1. When to assert false?
2. When to throw a FatalSystemException as you are suggesting above? Are you hinting that I should be throwing a RuntimeException and chaining it upwards here?
3. You and Andrew both are saying that don't wrap this exception in RecordFoundException and rethrow it?
Whould you elaborate a bit on how to go about deciding when to do what within the context of this assignment?
Regards to you both.
Bharat
 
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 Bharat

Also, I am not sure that I should be calling this [validateRecord(int recNo)] method from unlock and islocked methods? They both also throw RecordNotFoundException? For that matter, so do read, update, delete methods. I am a bit unsure of why Sun has those methods throwing RecordNotFoundExceptions?


For all those methods you mentioned - could anyone call them with an invalid record number (either outside of range or deleted)? If so, wouldn't you like to inform the user?

I am a bit unsure of:
1. When to assert false?


An assertion can be used anywhere where an event cannot happen. It can serve to indicate that you believe that the event cannot happen and that you are not catering for it anywhere else in your code.
In this particular case, if you assert false on InterruptedException, then anyone looking at your code knows that you believe that you will never get an InterruptedException. Furthermore if they change your exception handler so that it rethrows the InterruptedException, they know (hopefully) that they have to go and add exception handlers in the calling classes to handle this since you will not have done it.
The trouble with having an assert is that you may also have to think about what to do in the runtime environment. In the development environment you would normally switch assertions on so that if (in our example) an InterruptedException is thrown, the assert will be triggered and your application will exit with suitable error messages so that you know what happened. But in the client's runtime environment you almost certainly do not want assertion checking turned on, so what do you want to have happen here? Anything? Nothing?

2. When to throw a FatalSystemException as you are suggesting above? Are you hinting that I should be throwing a RuntimeException and chaining it upwards here?


Slightly more drastic than the assert. You are saying that the event should not have occured, and since it has occurred you do not believe your system should continue running at all.
If you want to do this, I would recommend you subclass RuntimeException, so you are throwing an exception that has a descriptive name so that any programmer can see what you are doing.

3. You and Andrew both are saying that don't wrap this exception in RecordFoundException and rethrow it?


Well the record was found wasn't it? And you were waiting for it to become available. So wrapping the exception in RecordNotFoundException is a bit misleading / confusing to the junior programmer trying to work out what is happening in the client side application.
In the real world you might be better of throwing a more generic exception (for example CannotLockException) which could then be subclassed into RecordNotFoundException, DeadLockException, InterruptedWhileWaitingException, TimeoutException ....
Does that help?
Regards, Andrew
 
Time is the best teacher, but unfortunately, it kills all of its students - Robin Williams. tiny ad:
Smokeless wood heat with a rocket mass heater
https://woodheat.net
reply
    Bookmark Topic Watch Topic
  • New Topic