• 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

recNo choice

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

first of all, thanks for this forum. Most of the questions I've been asking recently were deep in my mind and kind of stopped me from doing proper coding...

I've once again some more point I would like to discuss: the choice of recNo.

For of all, the use of it. In my URLyBird 1.2.2, it looks like:
- in the DBAccess interface I can see that deleting should make the record number and associated disk storage available for reuse
- the recNo is never shown to the user. Indeed, the UI displays a list of the records but without, AFAI got it, showing the actual record number
- the recNo is a long

As a matter of fact, on top of that, the recNo should support restart: the application should work the same way before and after restarting it.

Pondering all that and recNo reuse (cf Tracking "free" lines in a dedicated set), I'm pondering the use of the location in the file as the recno (it would the location of start of the record, so first status and then fields).
It would allow a simple handling of the record location (the recNo given is where to look for the content in the DB, no lookup in a map needed, only a synchronized block on the database when using it) as well as of the deleted ones (cf link above). Reusing the deleted rows allows as well for efficient use of disk space.

I see some drawbacks yet:
- someone could use an old recNo and get content which is in fact attached to a new recNo put at the same place. However, the fact that the recNo is neither given to the customer nor shown to the operator should prevent any issue of the kind. On top of that, the DBAccess file calls for such an use of the recNo (explicitly allowing for reuse).
- what about wrong/no more valid recno?
-- If the recono is simply wrong, it would result in a read of spooky content.=> could be checked by making sure the recno given is a multiple for recordLength (minus the offset)
-- If the record has been erased in between , it would read the db for nothing. => could be avoided by checking the number isn't in the deletedRow list, triggering again the need to synchronize it somehow
-- recNo > database.length: no idea of outcome, I've to check
=> a Set of current recNo would simplify the matter: recNo not in ? read/update/deleted ended ! It's still simpler than the map recNo<->location but not by far

what's your pick on it ? Am I missing the obvious ? :$


EDIT: more on drawbacks
 
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
I just used the position in the database file: 1st record in the database file = 0, 2nd record = 1,...

I also reused record numbers, so it could be that you have spooky content. But because you can't delete records, this is not an issue in the current assignment. So I decided (and documented): if deleted records is added as a new functionality, this problem has to be addressed (or just skipped by removing the "reuse of deleted entrues" from the code)
 
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

If you reuse record numbers there is always this possibility.

Client B reads record 2.
Client A deletes and updates record 2.
Client B books record 2.

Client B will book the wrong room in the wrong hotel because the record number is stored on the client.

Oracle's specification states that "Your user interface should be designed with the expectation of future functionality enhancements...". These enhancements would obviously include delete and create. So you should not reuse record numbers.

Rod

 
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rod Sinclair wrote:
Client B reads record 2.
Client A deletes and updates record 2.
Client B books record 2.



Well champ, that will depend on how you implement your locking mechanism. I too reused deleted entries when creating new records. We must implement the locking mechanism in a way that what you showed in your example could not happen. The thing is, you have to lock a record before reading it. Then you do what you have to do and unlock it. This way, in your example, client A could only delete record 2 after it was already updated (and things, like, "if a particular record already belongs to a client..." would be implemented in the business layer, but it isn't required for this assignment).
 
Rod Sinclair
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Consider this:

Client B locks record 2.
Client B reads record 2.
Client B unlocks record 2.

Client A locks record 2.
Client A deletes record 2.
Client A unlocks record 2.

Client A locks record 2.
Client A creates new record recNo 2 reused.
Client A unlocks record 2.

Client B now has stale data for record 2.

Client B locks record 2.
Client B books record 2, wrong hotel.
Client B unlocks record 2.

Rod
 
Roberto Perillo
Bartender
Posts: 2292
3
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rod Sinclair wrote:
Client A locks record 2.
Client A deletes record 2.
Client A unlocks record 2.

Client A locks record 2.
Client A creates new record recNo 2 reused.
Client A unlocks record 2.

Client B now has stale data for record 2.

Client B locks record 2.
Client B books record 2, wrong hotel.
Client B unlocks record 2.
Rod



Well, it isn't necessary to lock a record to create a new record. Also, in your scenario, you are trying to lock a record that doesn't exist anymore. In my case, when you try such a thing, a RecordNotFoundException is thrown. So what you are saying would never happen. Remember that you only need to lock a record to update or delete it.
 
Rod Sinclair
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If you reuse record numbers do you maintain a HashMap of record numbers and mark the ones that are deleted?
 
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

Rod Sinclair wrote:Oracle's specification states that "Your user interface should be designed with the expectation of future functionality enhancements...". These enhancements would obviously include delete and create. So you should not reuse record numbers.


I totally disagree. For now you can reuse record numbers if you want too. There is no support for deletion of records, so you don't have to consider the possibility of stale (spooky) records. My application could still be enhanced with functionality enhancements in the future. When delete-functionality is added to the (gui part of the) application, you have to add some mechanism to prevent a wrong hotel from being booked (could be something like your own version of optimistic locking for example). Or like I said before you can remove the reuse of deleted entries from your code.
But this enhancement can be implemented in different ways: add a delete in the GUI, a seperate batch-program deletes old records (and runs each night or week),... But now you don't have any idea about these enhancements and maybe there will never be a delete functionality. You don't know at all, everything's possible.

Rod Sinclair wrote:If you reuse record numbers do you maintain a HashMap of record numbers and mark the ones that are deleted?


I used a record cache, so if my Map has a null as value, that record is a deleted one. If you don't use a record cache, you could simply have a List (or a Queue) which keeps track of the deleted records. If the List is empty, create at the end of the file; if it's not,...
 
Rod Sinclair
Greenhorn
Posts: 22
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm not sure but I think that Oracle/Sun are expecting us to code for create and delete in which case you cannot reuse record numbers. I could be wrong on this though.
 
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
True, but your create/delete methods will be unreferenced in your project, because your GUI will only have search and book functionality
 
Norbert Lebenthal
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
well, I've read carefully once more the assignement, and in the end it's not clear that we have to implement all methods of the given interface. If we had, then, in my case at least, reuse of recNo looks like the way to go:


// Deletes a record, making the record number and associated disk
// storage available for reuse.
// Throws SecurityException if the record is locked with a cookie
// other than lockCookie.
public void deleteRecord(long recNo, long lockCookie)



anyway, I guess I won't do it in the end, I'll just throw a NonSupportedException.

 
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
my 2 cents:
  • reuse of deleted entries is NOT a must requirement, just a decision like any other
  • I'm very curious to see if you'll pass by implementing the methods which are not used by just throwing an UnsupportedOperationException
  •  
    Norbert Lebenthal
    Ranch Hand
    Posts: 74
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

  • I'm very curious to see if you'll pass by implementing the methods which are not used by just throwing an UnsupportedOperationException


  • now I'm confused (once more lol). I had the feeling that you skipped stuff which weren't required. On my assignment, the"top level" features that must be implemented are the following:
    * A client program with a graphical user interface that connects to the database
    * A data access system that provides record locking and a flexible search mechanism
    * Network server functionality for the database system

    It says nothing about deletion, so I was assuming this feature could be skipped (not present neither in the UI).

    Regarding the interface, it says:
    Required Interface
    Your data access class must be called "Data.java", must be in a package called "suncertify.db", and must implement the following interface:

    and on top of that, for deletion:
    // Deletes a record, making the record number and associated disk
    // storage available for reuse.

    So I don't get your approach: either it's not required and then can be safely skip, either it's required and then one should abide to what is said, namely to implement a way to have the number and associated disk storage available for reuse. As you might see, I don't get the intermediate approach it seems your took.
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Norbert -

    You must implement all methods in the interface. You quote from the specification "Your data access class must be called "Data.java", must be in a package called "suncertify.db", and must implement the following interface:".

    Roel - just because create/delete are not referenced in the project does not mean that you can reuse record numbers, plan for future functionality. You are not displaying impeccable logic.
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Howdy, Norbert!

    So champ, for the functionality of booking rooms, we normally have a method, like, bookRoom(), in the business layer, which uses the update() method of the Data class. In the end of the day, the create() and delete() methods won't be used, but they must be implemented as if they were used. So you'll also have to make sure that the client trying to delete a record is the same one who locked it in the first place. Like my good buddy Roel, I also reused deleted entries... I don't have the instructions with me right now, but as far as I remember, the comments of the create() method say something like "creates a new record possibly reusing a deleted entry", so you may choose not to reuse them. It's really up to you. But please, do implement the create() and delete() methods, for the sake of your voucher!

    Rod Sinclair wrote:Roel - just because create/delete are not referenced in the project does not mean that you can reuse record numbers, plan for future functionality. You are not displaying impeccable logic.



    But the comments of the create() method do mean that you can reuse record numbers. This is a choice: you may or may not choose to reuse them. I guess the part where you talk about "impeccable logic" is based on the fact that, in a real DBMS, once you delete a record, its primary key will never be reused, right? Please correct me if I'm wrong. But in this assignment, it says that a deleted entry can be reused. One reason for reusing deleted entries is that, if records are created and deleted, it is pretty likely that the file size will be smaller than if you were not reusing deleted entries. But this is just a choice. You may come up with better reasons to not reuse them.
     
    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
    The comment on top of the create method in the interface =

    instructions.html wrote:// Creates a new record in the database (possibly reusing a
    // deleted entry). Inserts the given data, and returns the record
    // number of the new record.


    So reusing record numbers is not a "must" requirement, it's your choice to implement or not to implement this behavior (in my application record numbers are used).

    About the given interface:

    Your data access class must be called "Data.java", must be in a package called "suncertify.db", and must implement the following interface:


    So implementing the interface is a "must" requirement. That raises of course 1 question for all unreferenced methods: is throwing an UnsupportedOperationException a valid implementation of such a method? It's a risk that could lead to failure (I did NOT take the risk and implemented these methods completely, used test cases to validate if they work as expected)

    Rod Sinclair wrote:You are not displaying impeccable logic.


    I made the choice to reuse record numbers. So it has nothing to do with logic, it's just a choice. And regarding these future enhancements: my application is easy to extend and enhance with new functionalities. And you have not a clue what these future enhancements will be at this moment, so why would you adjust your code to a possible future enhancement you think will be implemented, which might never be requested by the business people (or will need a total other implementation than you thought).
    This way of thinking is part of the agile mindset (philosophy). When you would be part of my team and you would make that remark, I just say YAGNI and it won't be taken care of If in a few months, the delete functionality is requested by the business people and they have made their mind up (and know what they want), we will discuss what needs to be changed/added/... to implement this functionality.
     
    Ranch Hand
    Posts: 222
    Google Web Toolkit Eclipse IDE Chrome
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The way I handled this is that I have a Map of record numbers and file positions (Map of int-to-int, not the actual file positions. Because every record as a constant length, I calculate actual position by another private function), and I map every record number to specified file position. Record numbers are not reused, however file positions are. Initially every record number is mapped to its position sequentially, record 1 to position 1, record 2 to position 2 etc. Later when you delete a record the position is moved to deletedPositions Queue. When creating a record I first check whether deletedPositions has something in it to reuse, and only if it is empty I create a new file position.

    Is this a way or does it fall under category of "too complicated for junior programmer"?
     
    Elchin Asgarli
    Ranch Hand
    Posts: 222
    Google Web Toolkit Eclipse IDE Chrome
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roberto Perillo wrote:The thing is, you have to lock a record before reading it. Then you do what you have to do and unlock it.



    Is this true for all versions of assignment? Because my read function has no locks inside of it.
    But of course on top of lock and unlock functions, I have my own collection of read/write locks for every record, and master read/write record for reading/updating that read/write record collection.
     
    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

    Elchin Asgarli wrote:Is this a way or does it fall under category of "too complicated for junior programmer"?


    Sounds ok to me

    Elchin Asgarli wrote:Is this true for all versions of assignment? Because my read function has no locks inside of it.


    You don't have to lock a record for reading. I guess Roberto was a bit too quick in his explanation, what he meant was. Before you book (update) a record, you'll lock it (now nothing else can happen with this record), then you can read the record (see if it is still available), update the record (with the customer id) and finally unlock the record.
    As a side note: you are not supposed to have lock and unlock method calls inside the update and delete methods! Locking, updating and unlocking a record should happen with 3 seperate method calls.
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Roel - we will have to agree to disagree on what is meant by designing for future functionality enhancements. In my design because I have not reused record numbers create and delete can be added without altering the way I deal with record numbers.

    Roberto - there is a difference between reusing the disk space occupied by a deleted entry and reusing the record number. Oracle suggest reusing the disk space but that does not mean that you can reuse the record number. In my design the create method over writes a deleted entry and the new record is assigned a new record number.

    In the example I gave earlier you spotted the mistake where I said I delete record 2 and then lock record 2 on create. Obviously I don't do this. I have given the example again, this time correct.

    Client B locks record 2.
    Client B reads record 2.
    Client B unlocks record 2.

    Client A locks record 2.
    Client A deletes record 2.
    Client A unlocks record 2.

    Client A creates new record recNo 2 reused.

    Client B now has stale data for record 2. A new record has been created in the database and assigned recNo 2.

    Client B locks record 2.
    Client B books record 2, wrong hotel.
    Client B unlocks record 2.

    If you reuse record numbers I cannot see how the above scenario can be avoided.
     
    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

    Rod Sinclair wrote:Client B locks record 2.
    Client B reads record 2.
    Client B unlocks record 2


    Locking and unlocking a record is only needed for update and delete, not to read one.

    Rod Sinclair wrote:If you reuse record numbers I cannot see how the above scenario can be avoided.


    Your own optimistic locking algorithm for example.
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:I guess Roberto was a bit too quick in his explanation, what he meant was. Before you book (update) a record, you'll lock it (now nothing else can happen with this record), then you can read the record (see if it is still available), update the record (with the customer id) and finally unlock the record.



    That's what I'm talking about!
     
    Elchin Asgarli
    Ranch Hand
    Posts: 222
    Google Web Toolkit Eclipse IDE Chrome
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Elchin Asgarli wrote:Is this a way or does it fall under category of "too complicated for junior programmer"?


    Sounds ok to me



    Good Btw, what does actually 'junior programmer' stand for? Someone with no or only few years of software development experience? Can I assume that he/she will have an SCJP or similar level of Java knowledge?

    Roel De Nijs wrote:
    You don't have to lock a record for reading. I guess Roberto was a bit too quick in his explanation, what he meant was. Before you book (update) a record, you'll lock it (now nothing else can happen with this record), then you can read the record (see if it is still available), update the record (with the customer id) and finally unlock the record.



    So reading right before the update is for verifying whether the record is still the one we used to fetch? If this is the case, then if I do NOT reuse record numbers like the way I described above, I should not have a problem with this, so I can skip this step, can't I?
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Elchin Asgarli wrote:So reading right before the update is for verifying whether the record is still the one we used to fetch?



    Well, actually it is to make sure that the record hasn't been booked already or hasn't been deleted.
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Roel - I lock a record in the read method before the calls to seek and readFully. This is because another thread could be updating the same record at the same time the read is taking place in which case read would return a corrupted record. I assume that you synchronize the entire read method to prevent this happening.

    An optimistic locking mechanism sounds complicated. It is simpler to not reuse record numbers and Oracle say keep it simple.
     
    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
    A junior programmer/developer is (for me) someone with 0-2 years of development experience. When I finished my education I had no SCJP, and my knowledge of Java was very limited (I even had no GUI/Swing experience) and also no real multi-threaded experience besides the usual suspect examples (BankAccount, CarwashWithDifferentLanes,...) to illustrate the problems.
    When developing my assignment I didn't think of the junior programmer all the time, I just used the KISS principle all the time

    Roberto Perillo wrote:

    Elchin Asgarli wrote:So reading right before the update is for verifying whether the record is still the one we used to fetch?



    Well, actually it is to make sure that the record hasn't been booked already or hasn't been deleted.


    I don't agree with Roberto (which is highly unusual ) When the record is deleted already, I would expect the lock method to throw the RecordNotFoundException. So when the lock succeeds, you have a valid (non-deleted) record and no other thread can modify or delete it. But the room could be booked already by another client (while in your table the room is still available). So in my opinion you can NOT skip this step, because double bookings are (or could be if the other person is a really cute girl )
     
    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

    Rod Sinclair wrote:Roel - I lock a record in the read method before the calls to seek and readFully. This is because another thread could be updating the same record at the same time the read is taking place in which case read would return a corrupted record. I assume that you synchronize the entire read method to prevent this happening.


    That has nothing to do with locking (and unlocking) a record, that's just making your class (and methods) thread-safe. Reading a record is just 1 call to the Data class and not 3 (lock, read, unlock) as you described in your post I quoted in one of my previous posts.

    Rod Sinclair wrote:An optimistic locking mechanism sounds complicated. It is simpler to not reuse record numbers and Oracle say keep it simple.


    That could be complicated indeed, but could be very easy too (just compare all the properties, or a subset, of the room you've got with the one with same recNo in the database). I didn't implement it of course, because it was not necessary in the current application. When deleting records is a new functional requirement, I'll decide what the consequences will be and depending on the given time and difficulty I'll take appropriate action.
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:I don't agree with Roberto (which is highly unusual ) When the record is deleted already, I would expect the lock method to throw the RecordNotFoundException. So when the lock succeeds, you have a valid (non-deleted) record and no other thread can modify or delete it.



    Oh, right right right. My answer was precipitate. In this case, I don't agree with myself either!
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Roel - are you sure that reading without any synchronization is thread-safe? There is a critical section of code in read.
     
    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

    Rod Sinclair wrote:Roel - are you sure that reading without any synchronization is thread-safe? There is a critical section of code in read.


    I have never mentioned you should read without synchronization. But there is a huge difference between locking and unlocking a record (using lock/unlock method) and using synchronization to make your method thread-safe.

    Code to read record 1:


    Code to update record 1:


    All 4 methods will have to be implemented in a thread-safe way. This can be done using different alternatives (mark every method synchronized, use synchronized block, make use of the new conccurency api,...)
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Roel - It sounds from your response that you do synchronize read. It would not work otherwise. I use the record locking mechanism provided by lock and unlock to achieve the same thing in read i.e. making critical sections of code threadsafe. My system is designed so that multiple threads can update and read different records at the same time because my synchronization is fine grained. Using synchronize locks the entire database.
     
    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
    Of course my methods are synchronized, that's one of the alternatives to make your Data class thread-safe. So if I would use your code and don't use lock/unlock when reading a record, it will not be thread-safe? And how did you make the create-method thread-safe (because no recNo exists at that moment to lock the record)? How do you make your lock/unlock methods thread-safe?
     
    Rod Sinclair
    Greenhorn
    Posts: 22
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Roel - here is the secret. I call lock and unlock inside the read method to lock the record, just around the critical section of code. You can use my read code without first locking and then unlocking. It is thread safe.

    I use a static lock object (java.util.concurrent.locks.Lock) that is shared amongst all instances of the Data class. In my lock method I first have to get a lock on the static lock object. I then check a static HashMap to see if the record is locked. If it is I wait if not I continue, enter the recNo in the HashMap locking the record. I then unlock the static lock object so another thread can get in.

    The create method is threadsafe because to execute create you first have to get a lock on the static lock object. Once this is achieved all other threads must wait. The create method is the only method that needs to be locked for the duration of execution.

    As I said previously delete and update can be executed in a threadsafe manner without synchronizing these methods. The record has already been locked in the lock method. As I said before the secret to maximum concurrency is not to make Data a Singleton. Then each instance of Data has its own handle to the raf which means that different records in the database can be read, updated and deleted concurrently. Each thread has its own pointer to the raf. Remember, local variables are threadsafe. Static variables are used to coordinate the locking.
     
    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

    Rod Sinclair wrote:here is the secret. I call lock and unlock inside the read method to lock the record, just around the critical section of code. You can use my read code without first locking and then unlocking. It is thread safe.


    All fine with me, but then just don't pretend like the client has to call lock and unlock seperately (like you did here) and I won't comment about.

    Rod Sinclair wrote:maximum concurrency


    Nice, but not a requirement of the assignment. You will not get more credit for your approach than I got for making my Data class a singleton and mark each method as synchronized. And so each approach will have its pros and cons. It's all about defending the choices you made, not about getting the most performant solution.
     
    Norbert Lebenthal
    Ranch Hand
    Posts: 74
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    while fine tuning my choices.txt, I stumbled upon this topic of record id generation and, similarly, the logical lock cookie generation.

    In the end, for both the record id and the cookie, what I really want is for these numbers is to be unique, like the same record id or cookie shouldn't be created twice over the application life span. The goal is to have no one asking for some record/cookie with some stale value and still get some result.

    This is a bit tricky to achieve, IMHO, since we don't persistently store the record id or cookies, so caring for restart is a bit hard.

    So, the need is for an UUID.

    However, AFAIK, Java doesn't provide a facility to generate UUID as long by default. The UUID.randomUUID().timestamp() calls throwing exception by default since the JVM generated UUID isn't a time based one.

    So, what I'm about to do is the following: having an util class to generated UUID and, in the first instance, to just do System.nanoTime() (and documenting this choice for sure).

    Edit bis, to make the matter clearer, the code is the following:

    What's your pick on that ?
     
    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

    Norbert Lebenthal wrote:What's your pick on that ?


    You wrote a whole lot of documentation for just 1 single line of code. I used the same System.nanoTime() to get my client identification number and just added in the choices.txt that in the future this "algorithm" could get improved (make more unique) if necessary. That's it!
     
    Norbert Lebenthal
    Ranch Hand
    Posts: 74
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:

    Norbert Lebenthal wrote:What's your pick on that ?


    You wrote a whole lot of documentation for just 1 single line of code. I used the same System.nanoTime() to get my client identification number and just added in the choices.txt that in the future this "algorithm" could get improved (make more unique) if necessary. That's it!



    well, that's the biggest comment in my app by far... however it's also the less clean stuff I do I think... Having done a bit more research, at work I would even consider using the least significant half of a generated UUID (cf http://stackoverflow.com/questions/325443/generate-uuid-in-java ), however I guess it's a bit over the top for SCJD!

    thanks again though, reading all these long posts is quite an endeavor...
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Howdy, Nono!

    Champ, regarding the comments, you could replace these comments for something like "Generates a unique id."

    Other than that, the purpose of this method is to generate a unique id for the lock cookie, right? It's just that it is only a line of code... do you think it is worth it to have a class and a method just for that? Also, I'm not a very fan of these utility static methods. Of course, they have to exist... look at the Collections class, for instance. But, if you can put this method in a class where this responsibility fits better, then you should go for it. In this case, I'd say that the generation of the cookie should be done in the lock() method. We could, for instance, have an interface with a method that returns a long, and we could have several implementations of it, but this certainly would only introduce unnecessary complexity.

    And as a final remark, I used System.currentTimeMillis() to identify the client. Today, I'd use the current Thread's id.
     
    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

    Roberto Perillo wrote:Today, I'd use the current Thread's id.


    If you use a thin client approach, you can take that approach. With a fat client (combined with RMI) this approach will fail, because you don't have the guarantee that subsequent calls are handled by the same thread. (I guess you'll know this one , just a small note for other people pursuing ocmjd certification)
     
    Roberto Perillo
    Bartender
    Posts: 2292
    3
    Eclipse IDE Spring Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Roel De Nijs wrote:If you use a thin client approach, you can take that approach.



    Correct. Today, my client would be a thin one, specially because it eases the solution in many aspects. Of course, it the client is a fat one, then one option is to use the System.currentTimeMillis() value, which is what I used.
     
    Those who dance are thought mad by those who hear not the music. This tiny ad plays the bagpipes:
    a bit of art, as a gift, the permaculture playing cards
    https://gardener-gift.com
    reply
      Bookmark Topic Watch Topic
    • New Topic