• 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
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

NX: URLYBird / my approach of the reading problem

 
Ranch Hand
Posts: 266
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Phil,
I know what you mean
I have changed the function as following:

I have implemented a private function matchingRecord(). I reduce the search to the fields name, location and owner. Is this correct?
What I'm wondering about is that I haven't seen in this forum a function like getRecords(). Should we not implement a function which return all the valid Records? Because when a client connects himself to the server he should get all valid Records for the GUI TableModel?
Regards
Ulrich
 
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 Ulrich,

Should we not implement a function which return all the valid Records? Because when a client connects himself to the server he should get all valid Records for the GUI TableModel?


Sorry for getting into your discussion with Phil.
It depends on your client implementation:
I've decided to provide JTextFields, not JComboBox, so in my case there is no need for this. TableModel will be empty at the start.
Best,
Vlad
 
Ulrich Heeger
Ranch Hand
Posts: 266
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi everyone,
I'm still a little bit confused how to implement my Data Access Layer.
1. I have a problem with the 48 h criterium.
2. I'm thinking about how to instantiate the DataSchema-Class
3. Checking the MagicCookie-value
4. How will the client determine which record will be booked.

concerning point 1:
I am thinking about to integrate within the update-method a control-mechanism to see if this Record is bookable. If not, it should throw a subclass of RecordNotFoundException. Is the only use of the update-method to store bookings or should I let it more general? If yes, I would have to check if the update is a booking.
concerning point 2:
I want to have a DataSchema-Singleton. This should be instantiated either when the server starts or in standalone-mode when the client connects the Data Access Layer. So there could be in the constructor of Data-Class a getSingletonInstance-call.
The DataSchema-instance would store the MagicCookie-value, the Length of each Field, the location of the db-file etc.
concerning point 3:
So each time, when a new Client connects, the MagicCookie-value will be checked.
Should I check the MagicCookie-value each time the client access the db.file or only once?
concerning point 4:
When a GUI client wants to book a Record, the server gets the Recordnumber from the GUI client, so it knows which record to update. But know I have a problem. For example, the GUI client shows RecordNumber 5.
In the meantime the Record with Number 5 has been deleted in the db.file and a new Record has been added at this position. So the new Record Number 5 is not the old one. Now the GUI client selects the Record 5, locked it, update it and unlocked, what won't be a problem. But the GUI client has now booked the new Record and not the old one. Can this occur?
I'm not still familiar with GUI and the TableModell, but I want to anticipate some problems which may occur in interaction with a GUI client.
Thanks in advance
Greetings & Regards
Ulrich
 
Ulrich Heeger
Ranch Hand
Posts: 266
  • 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.

I've decided to provide JTextFields, not JComboBox, so in my case there is no need for this. TableModel will be empty at the start.


So you use only the find-method().Whow, that's
Vlad, I will benefit from this occasion and annoy you with another question
Because some lines before you wrote:


I guess you ment a mutex.
If so, you don't need a separate static object. you have already one: reservedRecords. You can synchronize all you public methods on this objects.
To my opinion it should be Ok. That is what I am doing.


Sorry for asking twice, but concerning thread safety I'm a little bit paranoid :
So no concurrent reading is allowed? And that is ok?
Many greetings
Ulrich
 
Bartender
Posts: 1872
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Ulrich,

I know what you mean


Well, I meant something else ...
  • At the very first begining of findCriteria(), you should identify the case where all criteria are null. In that case, you must return an array of all valid recNos (not deleted), which, depending on your implementation (if you know which records are deleted), may be performed without any read in the file.
  • I know that you didn't implement a cache. If you did so to save memory, the fact that you pre-read all records in an ArrayList in findByCriteria() is inconsistent with your choice. As you have one instance of Data per client, think of what happens when say 5 clients perform a findByCriteria concurrently. Now if you chose to not implement a cache for simplicity, just notice that if your ArrayList allRecords was replaced by a static ArrayList cache, it would be as simple as you do now, though far more efficient.
  • matchingRecords is an ArrayList. Why ? Your new code is not complete (and does not compile anymore BTW), but I remember that you had a call to matchingRecords.contains(). This performs a sequential search in the backing array (slow) and you must call it because before adding a record to it, you must make sure the record is not already in the list (because ArrayList allows duplicates). If you implement matchingRecords as a TreeSet (or even a HashSet as you don't need to have the records sorted), you save the call to that slow contains().
  • "String[] searchFields = {buffer[1], buffer[2], buffer[7]}" : I think that you must not restrict the search that way. findByCriteria() is described in the interface as a generic find function, and must stay generic IMO.


  • Best,
    Phil.
     
    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 Ulrich,

    Sorry for asking twice, but concerning thread safety I'm a little bit paranoid


    You are not alone. I am also...

    So no concurrent reading is allowed? And that is ok?


    Correct.
    I have first implemented ReadWriteLock mechanism. It is extremelly cool idea. Then I realized that I am not able to provide a simple implementation of Data class. It has some small things. If they are changed/handled incorrectly by a "junior programmer" it would lead to dead-locks. So, I gave up, but Phil is happy with this ReadWriteLock solution (concurrent read/exclusive write). I have decided to move to extremely simple solution, which I mentioned already in the topic. Andrew used something the same (I synchronize all methods, but Andrew did some "tricks" with find()). Andrew has got very good scores for it. So, I am sure, it is Ok. I do the same.
    Best,
    Vlad
     
    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 Phil,

    as you don't need to have the records sorted


    I would argue this. It depends on. I don't perform any sorting in my client, so I beleive it is good idea for server to deliver sorted set of records. I used TreeSet, but then Jim convinced me that a List is much more understandable for "junior programmer" then TreeSet.

    Best,
    Vlad
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Ulrich,
    1. Data.Update() should stay general (same as for findByCriteria). If you need to check if a room is still bookable, it should be the caller's job IMO.
    2. What's the question ?
    3. Only once.
    4. Server-side, before booking, you could make sure that the room is still bookable (still exists, not booked by soeone else), but also that the record didn't change. In the first case, you could throw some UnbookableRoomException and in the second some RecordChangedException.
    Best,
    Phil.
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad,


    Hi Phil,
    quote:
    --------------------------------------------------------------------------------
    as you don't need to have the records sorted
    --------------------------------------------------------------------------------
    I would argue this. It depends on. I don't perform any sorting in my client, so I beleive it is good idea for server to deliver sorted set of records.


    That's why I mentioned TreeSet too. But think of the fact that as deleted records are reused, recNos order is quite arbitrary anyway.


    I used TreeSet, but then Jim convinced me that a List is much more understandable for "junior programmer" then TreeSet


    Well, it's quite rare that I disagree with Jim, but that's the case here. Remember when you studied for SCJP : you had to know the whole collections API. There are a few Lists, Maps, Sets and any junior Java programers should know what there are ... or just check in the API doc what they are.
    Best,
    Phil.
    [ September 22, 2003: Message edited by: Philippe Maquet ]
     
    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 Phil,


    That's why I mentioned TreeSet too. But think of the fact that as deleted records are reused, recNos order probably has not much sense.


    That is correct. Moreover, no database provides sorted resultset by default.
    Agreed.

    That is correct, but there is one more argument against using TreeSet:
    sorting is not performant
    I think it is a matter of taste. I dediced to deliver sorted set and I have choisen List instead of TreeSet. If you say that result set shouldn't not be sorted (and it is actually reasonable), of course, HashSet is better than a List.
    Best,
    Vlad
     
    Wanderer
    Posts: 18671
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Well, it's quite rare that I disagree with Jim, but that's the case here.
    Ack! Heresy! Smite the unbeliever!

    Mmmm, actually I think we'd probably still agree; my preference for using a List was in a somewhat different context. Though I'm not entirely sure I understand the context here, as I don't see the code that uses contains() as part of the find() method. But for my application,
  • All record data is kept in memory. Thus there's no need for any Map using recNo as key - a List works fine, and recNo is the index. If you've got a structure like this, you might as well put locking info there too; there's no need for a separate structure for locked records (e.g. the HashMap that most others seem to use here).
  • The find() method is going to be O(N) anyway, since it needs to be able to find inexact matches. String comparisons need to be done with startsWith() rather than equals(). So I saw no use for contains().
  • By iterating through the whole List of records once, the found results come out naturally sorted in the same order the List was, which is by recNo. No other sort order seemed necessary.


  • For other designs, one or more of these assumptions may be invalid. (Most commonly, the first.) If you don't cache everything, then using Maps and Sets to keep track of certain things becomes more useful. And if you have a requirement that results be sorted a particular way, then TreeMap/TreeSet are worth considering. (Though Collections.sort() and Arrays.sort() work well too.)
    <digression>
    Now actually there are ways to get find()'s performance to be better than O(N). E.g. for searching by name, create a TreeMap with name as key. Since multiple records can use the same name, this must be a one-to-many map, meaning each value is actually a List of the records which have the same name. To find all records with name starting with "Fred", don't use get("Fred") since that gives only exact matches. Instead use map.subMap("Fred", "Frec"). This will find "Fred" as well as "Freddy". But it won't find "FRED". (Though you could use toLowerCase() to convert all keys before putting them in the TreeMap, and to convert search criteria as well.) If you need to search for other criteria as well, then you may still need to iterate through the result of subMap() to find only those records satisfying the additional criteria (e.g. for matching location as well as name). But using the subMap() allows you to do a linear search through a much smaller set of records than if you'd iterated through all N records.
    The one big advantage of this approach is that it can make searches a lot faster. The disadvanteges are:
  • Requires more memory (not a big deal, relatively, if you're already using a full-caching solution, but significant otherwise)
  • Adds substantial complexity
  • Provides no benefit if future enhancements require more flexible matching, e.g. using regexes
  • I chose not to implement this type of searching, due primarily to the added complexity. But those of you using TreeSets for searching might want to consider this possibility further.
    </digression>
    [ September 22, 2003: Message edited by: Jim Yingst ]
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Jim,

    Ack! Heresy! Smite the unbeliever!



    Mmmm, I think we'd probably still agree; my preference for using a List was in a somewhat different context, I believe. Though I'm not entirely sure I understand the context here.


    Yes we agree here, because the example you give of using an ArrayList in your application is a good-use example. What I criticized was the use of an ArrayList to temporarily store matching records (recNos as Longs) while findByCriteria() is running, like Ulrich does. Here is what I wrote about it :

    matchingRecords is an ArrayList. Why ? Your new code is not complete (and does not compile anymore BTW), but I remember that you had a call to matchingRecords.contains(). This performs a sequential search in the backing array (slow) and you must call it because before adding a record to it, you must make sure the record is not already in the list (because ArrayList allows duplicates). If you implement matchingRecords as a TreeSet (or even a HashSet as you don't need to have the records sorted), you save the call to that slow contains().


    Now about your "digression" : I use a similar technique from my earliest db design : fields individually may be indexed (or not). If a field is indexed, it owns an instance of my class Index, backed by a TreeMap of TreeSets of recNos. My findByCriteria() method uses indexed fields first, starting with the indexes with the highest number of keys. As you mention it, this technique allows you to do a linear search through a much smaller set of records.
    Best,
    Phil.
    [ September 22, 2003: Message edited by: Philippe Maquet ]
     
    Jim Yingst
    Wanderer
    Posts: 18671
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Philippe: cool, glad to see someone is using TreeMap this way. I should say that the "added complexity" isn't necessarily too great; it's probably possible to refactor the code so that it's reasonably easy for everyone to understand. I was just too lazy to do this myself.
    One other benefit to using TreeMaps for indexed searching like this: if your GUI design includes JComboBoxes which list all values of a given field, then it may well be useful to give the server a method for returning all unique values of a given field (ideally, in sorted order). Otherwise the GUI is going to heve to read each and every record over the network in order to build its list of unique values. So it's nice if the server already maintains a complete sorted list of unique field values (for those fields you will want to search on), so that the list can be sent t clients on request, much more efficiently than if the server had to build such a list anew each time it was requested. The TreeMaps serve this added function nicely, since you can get a keySet() which iterates in sorted order. (Ummm, unless you've done toLowerCase() as I suggested earlier, which raises other complications again.)
    Actually I have added a getUniqueValues(int fieldIndex) method to my server in order to populate the drop-down fields, but currently the server builds a new TreeSet on the spot, rather than maintaining one trough all update()/create()/delete() calls. It's not as efficient as it could be, but it'spretty simple. And truthfully, in my current design the RMI networking performance is a bigger performance bottleneck than anything else remaining; there's little sense in further DB optimizations unless I first replaced RMI with sockets. And I'm not going to do that at this point, given that performance isn't supposed to be a big consideration anyway. I've optimized things that were easy to optimize without adding complexity, but I think further changes like going to sockets falls outside that category now, considering my current design. So this part of the conversation has been purely hypothetical from my viewpoint, but I'm glad at least one person out there has been doing stuff like this. Cheers...
     
    Jim Yingst
    Wanderer
    Posts: 18671
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Looking through past discussion in this thread, there seems to still be an open issue about the use of notifyAll() in the reserverDVD() method in Max's book, p. 125. (This corresponds to the lock() method most of us have in our server code.) I agree with Vlad and others who can't see any use at all for the notifyAll() here. Max seems to think it's useful for any threads which are attempting to enter a sync block, that they will somehow benefit from this notifyAll(). That's not the case. Vlad correctly observes that there's a difference between waiting (due to wait()) and attemping to acquire a sync lock. The notify() and notifyAll() methods only affect thread(s) which are currently wait()ing; they have no effect on threads attempting to acquire a sync lock (meaning, attempting to enter a synchronized block). For threads attempting to acquire a sync lock, the only thing they need to "wait" for is for whatever thread currently has the sync lock, to either exit the associated sync block or method, OR call wait(), which will also release the held sync lock. Once that happens any and all threads which are attempting to acquire that sync lock will have a chane to acquire it. Of course only one will get the sync lock at a time, but each time the sync block is exited, a new thread will be able to acquire the sync lock. Notify() and notifyAll() have no effect on this process.
    This topic was previously discussed here - see the last four posts from Feb 27-28, from Max, PdH, and myself. The JLS and API offer no support for the idea that a thread attempting to acquire a lock is in a wait state. Instead, JLS 17.13 is clear that when a thread exits a synchronized block, it will unlock the sync monitor (note that this use of "unlock" is not the same as the unlock() method of our DB classes). This unlock action is all the "notification" that "waiting" threads need. (Where "wait" in this case is used exclusively to mean threads which are attempting to acquire a sync lock, as opposed to threads which are actually executing a wait().)
    Based on past experience, this can probably lead to a very lengthy discussion in which nothing is ultimately agreed on, but the short version is: the notifyAll() on p. 129 serves no purpose at all. It doesn't really hurt anything either, other than waste a few CPU cycles waking up threads which are unable to actually do anything. Any waiting threads (now meaning threads executing wait(), hence the lack of quote marks) will get all the notification they need (or can make use of) from the notifyAll() in releaseDVD(), on p. 131. (Corresponding to the unlock()method for most of us.) Notify waiting threads when at least one reserved DVD has been released, since it may be the record they're wait()ing for. Don't bother them when you've just reserved another DVD, as the waiting threads really don't have any reason to care.
    [ September 22, 2003: Message edited by: Jim Yingst ]
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Phil,
    thanks a lot for your comments.


    1. At the very first begining of findCriteria(), you should identify the case where all criteria are null. In that case, you must return an array of all valid recNos (not deleted), which, depending on your implementation (if you know which records are deleted), may be performed without any read in the file.
    ...
    4. "String[] searchFields = {buffer[1], buffer[2], buffer[7]}" : I think that you must not restrict the search that way. findByCriteria() is described in the interface as a generic find function, and must stay generic IMO.


    Yes, it's really important to read carefully the instructions
    I'm sorry that I haven't. So I don't need also the getRecords()-method.


    I know that you didn't implement a cache. If you did so to save memory, the fact that you pre-read all records in an ArrayList in findByCriteria() is inconsistent with your choice. As you have one instance of Data per client, think of what happens when say 5 clients perform a findByCriteria concurrently. Now if you chose to not implement a cache for simplicity, just notice that if your ArrayList allRecords was replaced by a static ArrayList cache, it would be as simple as you do now, though far more efficient.


    After this discussion I'm seriously thinking about to use a cache. The cache should of course be updated by update(), delete() and add()-call,yes?
    By the way, have you implemented the delete() and add()-method? I don't know if we should?

    matchingRecords is an ArrayList. Why ? Your new code is not complete (and does not compile anymore BTW), but I remember that you had a call to matchingRecords.contains(). This performs a sequential search in the backing array (slow) and you must call it because before adding a record to it, you must make sure the record is not already in the list (because ArrayList allows duplicates). If you implement matchingRecords as a TreeSet (or even a HashSet as you don't need to have the records sorted), you save the call to that slow contains().


    I was also thinking to this, but here I'm iterating through all Records and if it matches with one Element of criteria, I will put the Record to matchingRecords. So there won't be twice the same Record at the ArrayList.
    Regards
    Ulrich
     
    Jim Yingst
    Wanderer
    Posts: 18671
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    By the way, have you implemented the delete() and add()-method? I don't know if we should?
    The general consensus seems to be: the methods certainly need to be implemented in the sense that, at a minimum, your data access class has methods with the correct signature, so that the required interface is implemented. Additionally most of us fell strongly that the methods, if called, should actually implement the described behavior. However the GUI's requirements do not seem to actually require any create() or delete(). So you will probably have methods implemented by your server which are never called by your GUI client. Just assume that you are designing for possible future enhancements. They've asked you to implement an interface for the server; maybe someone else will write another client which uses create() or delete(), or maybe they want to add this to your own code later on.
    [ September 22, 2003: Message edited by: Jim Yingst ]
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Phil,
    sorry, but I have still a few questions concerning your second reply.


    4. Server-side, before booking, you could make sure that the room is still bookable (still exists, not booked by soeone else), but also that the record didn't change. In the first case, you could throw some UnbookableRoomException and in the second some RecordChangedException.


    To resolve this problem we could go following process:
    lock it, read it, check it:
    if ok update it,
    if not throw UnbookableRoomException, RecordChangeException
    But in this case I will change my book-method in my Adapter-Class.
    I would pass not only the RecordNumber as argument, but also the values of all fields. So the checking process will be within the book-method.
    Is that similar to the way you intend?
    Thanks a lot in advance,
    bonne nuit
    Ulrich
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad,
    thanks for your answer.
    I think I will also use a mutex.
    Greetings,
    Ulrich
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Jim,
    you wrote:

    The general consensus is: the methods certainly need to be implemented in the sense that, at a minimum, you data access class has methods with the correct signature, so that the required interface is implemented. Additionally most of us fell strongly that the methods, if called, should actually implement the described behavior. However the GUI's requirements do not seem to actually require any create() or delete(). So you will probably have method implemented by your server which are never called by your GUI client. Just assume that you are designing for possible future enhancements. They've asked you to implement an interface for the server; maybe someone else will write another client which uses create() or delete(), or maybe they want to add this to your own code later on.


    Good to know, thank you,
    Regards
    Ulrich
     
    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 Jim,

    I agree with Vlad and others who can't see any use at all for the notifyAll() here.
    ...
    Based on past experience, this can probably lead to a very lengthy discussion in which nothing is ultimately agreed on, but the short version is: the notifyAll() on p. 129 serves no purpose at all. It doesn't really hurt anything either, other than waste a few CPU cycles waking up threads which are unable to actually do anything.


    Cool, one more supporter! Max where are you? Come back on the ring, let's fight, now I am not alone!

    By the way, have you implemented the delete() and add()-method? I don't know if we should? So you will probably have methods implemented by your server which are never called by your GUI client.


    I 've implemented all methods on the server, but not on the GUI client.
    I am 100% sure it is right.
    I guess Sun has already RemoteAdapter to DB interface, all it methods will be automatically tested (I don't see other thing, which Sun can automatically test).
    Best,
    Vlad
    [changed one [ code ] tag to [ quote ] to fix page appearance.- Jim]
    [ September 23, 2003: Message edited by: Jim Yingst ]
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Jim,
    Jim:
    Philippe: cool, glad to see someone is using TreeMap this way. I should say that the "added complexity" isn't necessarily too great; it's probably possible to refactor the code so that it's reasonably easy for everyone to understand. I was just too lazy to do this myself.

    Jim, cool to get reassured on the technique I use, because it seems that I am quite alone to use optional field in-memory Indexes.
    Jim:
    Actually I have added a getUniqueValues(int fieldIndex) method to my server in order to populate the drop-down fields, but currently the server builds a new TreeSet on the spot, rather than maintaining one trough all update()/create()/delete() calls. It's not as efficient as it could be, but it'spretty simple.

    I called it getDistinctValues :

    As you can see, when a Field is not indexed, it owns a private TreeMap instance named valuesMap. For each key in the map, instead of a TreeSet of recNos (like in Index), I have the number of occurences of that key as a Long value. There are a few advantages to it :
  • getDistinctValues() is as fast on any field, indexed or not
  • a method distinctValuesCount() may help a DBA (through some monitoring view) to decide which fields are good candidates to get indexed (it will be the case only if the returned number is high in comparison with the db size). For example, on a 100000 records table, field smoking will still have 2 distinct values (stupid to index it), while location could have 1500 (better candidate for indexing)
  • A not indexed field can be queried for valueOccurences() of a given key range (TreeMap.subMap() is quite handy), giving a way to speed up linear search in the case where no records are found (no need to read anything in the file or in cache if valueOccurences() of any of the search criteria corresponding to not indexed fields returns 0)


  • Of course that TreeMap must be kept up-to-date as Indexes after create/update/delete operations, but it's not a big deal.
    Data delegates it to its MetaData through three methods (recordAdded, recordRemoved, recordUpdated), which in turn delegates the job to each of its fields (same methods at the Field level). If a Field is indexed, the job is passed to its Index (still same method names), else it just updates its valuesMap.
    I have a question for you : To support wildcard search ("Fred" matches "Freddy"), Index uses TreeMap.subMap(fromKey, toKey) with fromKey being "Fred" and toKey being Field.maxValue("Fred"). Is that maxValue() method correct IYO ? (it works fine but...)

    Jim:
    there's little sense in further DB optimizations unless I first replaced RMI with sockets.

    Don't talk sockets to me, Jim ! I tried to initiate a big sockets discussion in Anybody interested in a sockets discussion ? and I never enjoyed seeing you and Max coming in... BTW, I never finished the description of my sockets solution there. I had still a few little points :
  • Two-way communication / Optional callbacks
  • Hand shake
  • The two main classes (singleton ConnectionsManager server-side and Connection client-side)


  • I anybody is interested, I'll finish it, promised !
    Best,
    Phil.
    [ September 23, 2003: Message edited by: Philippe Maquet ]
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Ulrich,

    After this discussion I'm seriously thinking about to use a cache. The cache should of course be updated by update(), delete() and add()-call,yes?


    Yes, but it's quite simple.

    By the way, have you implemented the delete() and add()-method? I don't know if we should?


    Yes, and you must do it.

    I was also thinking to this, but here I'm iterating through all Records and if it matches with one Element of criteria, I will put the Record to matchingRecords. So there won't be twice the same Record at the ArrayList.


    Good point. Don't forget it must matches all criteria, not just "one Element of criteria". I don't know why I remember that you call contains() on your ArrayList in a previous version. But it's OK now anyway.


    sorry, but I have still a few questions concerning your second reply.
    quote:
    --------------------------------------------------------------------------------

    4. Server-side, before booking, you could make sure that the room is still bookable (still exists, not booked by soeone else), but also that the record didn't change. In the first case, you could throw some UnbookableRoomException and in the second some RecordChangedException.
    --------------------------------------------------------------------------------
    To resolve this problem we could go following process:
    lock it, read it, check it:
    if ok update it,
    if not throw UnbookableRoomException, RecordChangeException
    But in this case I will change my book-method in my Adapter-Class.
    I would pass not only the RecordNumber as argument, but also the values of all fields. So the checking process will be within the book-method.
    Is that similar to the way you intend?


    Exactly that !
    Best,
    Phil.
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad and Jim,

    (Vlad)
    Hi Jim,
    quote:
    --------------------------------------------------------------------------------
    I agree with Vlad and others who can't see any use at all for the notifyAll() here.
    ...
    Based on past experience, this can probably lead to a very lengthy discussion in which nothing is ultimately agreed on, but the short version is: the notifyAll() on p. 129 serves no purpose at all. It doesn't really hurt anything either, other than waste a few CPU cycles waking up threads which are unable to actually do anything.
    --------------------------------------------------------------------------------
    Cool, one more supporter! Max where are you? Come back on the ring, let's fight, now I am not alone!


    That's maybe why we don't see Max around here for a few days : maybe he hopes we'll forget it in the meantime !
    Best,
    Phil.
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Jim, hi Philippe,
    sorry Jim, that I haven't replied to your advices because I didn't know if you answered my questions or your comments were more general.
    (The truth is I was afraid to not understand the topic of your and Phils discussion )
    I'm still a poor beginner searching his way through the difficult world of Java programmation
    Now, I give me a little time to try to follow your and Phil's discussion and I noticed that there are a lot of usefull points for me
    But, like always, some questions emerge for me:
    1. Concerning the discussion for the use of TreeMap is due to the point the assignement requires:


    It must allow the user to search the data for all records, or for records where the name and/or location fields exactly match values specified by the user.


    Beside the discussion if to use a TreeMap or not, where have your guys implemented this specified find-method? I mean, have you integrated it within the given findBycriteria-method or have you created new ones?
    2. You were debatting if the return collection should be sorted or not. Why? Because the Records should be sorted for example alphabetically to give a structure to the View?
    Regards & Greetings
    Ulrich
    [ September 23, 2003: Message edited by: Ulrich Heeger ]
     
    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 Ulrich,
    Could you please edit your mail

    concerning point 2:....


    It is inside CODE Tag. YOu should switch it to QUOUTE, otherwise the whole format is at the moment garbled.

    Tx,
    Vlad
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Ulrich,

    where have your guys implemented this specified find-method? I mean, have you integrated it within the given findBycriteria-method or have you created new ones?


    I would say within findByCriteria() itself, except that it delegates its job to a private doFindByCriteria() method. I did this because I added an overload findByCriteria() which accepts criteria ranges (I needed it to take easily the 48 hours time range into account).


    2. You were debatting if the return collection should be sorted or not. Why? Because the Records should be sorted for example alphabetically to give a structure to the View?


    No, not because of that (I think that if you want to implement sort of your search result sets, it could be done dynamically client-side, for example when a user clicks on a column header). I just think that having the recNos returned by findByCriteria() sorted or not is not important, because recNos represent nothing. If deleted records were not reused, recNos could be an indication of creation order. But as they are, recNos are just temporary references to records with no special meaning.
    Now about the Singleton. Typically, a singleton class is responsible to instantiate its only instance by itself. Here is an example :

    So, if you make your DataSchema a singleton, Data simply could call its getInstance() method from its constructor.
    Best,
    Phil.
    PS: What happens with this thread ?! The whole second page is nearly unreadable except last Ulrich's post...
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad,
    thanks for your advice. I got a little trouble editing it, so I post it once more. Sorry that the chronology of the thread is now disturbed
    Hi Phil,
    What would I do without your help and Vlads, Bharats, Jims, Maxs, Andrews and the others?
    I would remain totally lost in the big jungle of Java programmation
    I forgot to clarify one question.
    I wrote:



    concerning point 2:
    I want to have a DataSchema-Singleton. This should be instantiated either when the server starts or in standalone-mode when the client connects the Data Access Layer. So there could be in the constructor of Data-Class a getSingletonInstance-call.
    The DataSchema-instance would store the MagicCookie-value, the Length of each Field, the location of the db-file etc.


    So I was thinking about when the Singleton-Instance should be created.
    Because Andre wrote in this thread:


    I believe that on application startup (both stand alone client and server) you should verify the cookie.


    I don't know if there should be at the server a separate call to instantiate this singleton or should I include the singleton-creation when the first client is getting his Data-Class (in this second case, there would be within the constructor of Data-Class a control if the Singleton-Instance allready exist or not, in the first case, the Singleton-Instance allready exist due to the startup of the server.
    Perhaps I'm worring about to specific questions but I'm a poor ... (You see this will be in future my justification to keep asking idiot questions
    Regards & greetings
    Ulrich
    [ September 23, 2003: Message edited by: Ulrich Heeger ]
    [ September 23, 2003: Message edited by: Ulrich Heeger ]
     
    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 Ulrich,

    The difference is that Phil's Singletone is so-called lazy initialization: it will be first initialized when getInstance() is first called.
    The one I showed above is initialized immidiately. Look at it carefully : its getinstance() method is not synchronized!!!
    I just wanted to bring some confusion in the topic
    Now I would differ the question about magic_cookie and time of Singletone initialization. It depends on your implementation. My magic cookie is a static constant in this class (it means it is initialized independantly fro the object of this Singletone). So I can compare magic_cookie in MetaData class with the one in file before Singletone is initialzed.
    I personally think it is much better idea to iniatiate the Singletone on start of the server. If something goes wrong you will see it. If you do it upon first client request, you would detect problems to late!
    Best,
    Vlad
    [ September 23, 2003: Message edited by: Vlad Rabkin ]
    [ September 23, 2003: Message edited by: Vlad Rabkin ]
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad,
    Thank you
    Regards
    Ulrich
     
    Ranch Hand
    Posts: 231
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    After reading this page. You may be interested in my approch. My DBMetaData sounds like you DataSchema.

    This gives me a singleton of DBMetaData which I am using in both Data and DBAdapter.
    Let me know what you think.
    Chris
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Phil,
    thank you for your comments. I'm trying to integrate all what I learned in this thread in my Data and DataAdapter-Class.
    So I will soon post my find-method(s) in both classes here in this thread

    Regards
    Ulrich
    [ September 23, 2003: Message edited by: Ulrich Heeger ]
    [ September 23, 2003: Message edited by: Ulrich Heeger ]
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Chris,
    elegant approach. Thank you.
    Ulrich
     
    Jim Yingst
    Wanderer
    Posts: 18671
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    [Ulrich]: sorry Jim, that I haven't replied to your advices because I didn't know if you answered my questions or your comments were more general.
    (The truth is I was afraid to not understand the topic of your and Phils discussion )

    No problem, Ulrich. I haven't read the whole thread carefully myself - for most of your points, it looked like others were already answering them satisfactorally, so I left them alone. I was just replying to some unresolved issues I had an interest in. And as for what Philippe and I are talking about - well, I did label it "digression". Feel free to ignore it. Since we were talking about using TreeSet or TreeMap in the find() method, I wanted to acknowledge that they could play a useful role in the design. It's just a more elaborate design than most people are interested in making. Ignore for now; after you've spent some time working on your project and seeing how the various parts will fit together you may want to read this thread again to see if if makes more sense. Or not - you can completely skip the <digression> without damaging your score.
    [Philippe]: Don't talk sockets to me, Jim ! I tried to initiate a big sockets discussion in Anybody interested in a sockets discussion ? and I never enjoyed seeing you and Max coming in...
    Sorry, Philippe. In general I would have been interested, but I was trying to cut down on distractions at the time, and I'd already chosen to go with RMI, so I didn't want to start down the other road. If I liked it too much I might've ended up redesigning everything. Cheers...
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi,
    I wrote above:

    Yes, it's really important to read carefully the instructions


    Shame on me, I think I have all the time misunderstood the signature of findByCriteria(String[]criteria:

    Field n in the database file is described by
    criteria[n].


    So for example, if the User would insert "er" in the searchField, so there would be a call: findByCriteria("er", "er", "er", "er", "er", "er","er")
    And for example the specified search for name or location would be:
    findByCriteria("Palace", "", "", "", "", "", "")
    and
    findByCriteria("", "Pleasantville", "", "", "", "", "")
    I'm right?
    or is it:
    findByCriteria("Palace", null, null, null, null, null, null)
    and
    findByCriteria(null, "Pleasantville", null, null, null, null, null)?
    Thanks in advance,
    Ulrich
     
    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 Ulrich,

    I'm right?


    Yeap! Don't forget the according URLyBird assignement null value in array:
    {"hh", "hh", null, "kk",...} means "any".
    So request to find by hotel/name should look like this:
    {"hotel", "city", null, null, null, null}
    Sorry, that I didn't mention it earlier, I though I knew it.
    Best,
    Vlad
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad,
    sorry, I have one more question concerning the MagicCookie
    You wrote:

    My magic cookie is a static constant in this class (it means it is initialized independantly fro the object of this Singletone). So I can compare magic_cookie in MetaData class with the one in file before Singletone is initialzed.


    Does it mean that you have assigned your MagicCookie a value before the db.file has been readed the first time? So you have it hardcoded in DataSchema-Class?
    Regards
    Ulrich
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Vlad
    While I was writing my second question you've allready answered my first one.Wow, that's incredible, thanks a lot.
    Ulrich
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Phil,
    I'm a little bit confused by your second findByCriteria-method.
    Why shouldn't we have such an overloaded method?
    Because I wrote above:


    Concerning the 48h criterium:
    I am thinking about to integrate within the update-method a control-mechanism to see if this Record is bookable. If not, it should throw a subclass of RecordNotFoundException. Is the only use of the update-method to store bookings or should I let it more general? If yes, I would have to check if the update is a booking.


    You answered:

    1. Data.Update() should stay general (same as for findByCriteria). If you need to check if a room is still bookable, it should be the caller's job IMO.


    is it not only during the update that the 48h criterium is to be considered? Why should I integrate within the find-method such a control-mechanism?
    Regards & thanks in advance
    Ulrich
     
    Philippe Maquet
    Bartender
    Posts: 1872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Ulrich,
    In this thread, you'll see my interpretation of this 48h criteria. But the question is also : should we only display bookable rooms to the user ? My answer is yes, but I know that other people think differently.

    Does it mean that you have assigned your MagicCookie a value before the db.file has been readed the first time?


    Answering for Vlad, I say yes.

    So you have it hardcoded in DataSchema-Class?


    It seems well. A better place IMO would be somewhere at the application level. The suncertify.db package looks like a reusable package and the magic cookie could vary in different tables and/or applications.
    Best,
    Phil.
    PS: As so often in such huge threads, we are now so far from the original reading problem ! Don't hesitate to initiate new threads when/if you feel need it.
     
    Ulrich Heeger
    Ranch Hand
    Posts: 266
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Hi Philippe,
    thank you

    PS: As so often in such huge threads, we are now so far from the original reading problem ! Don't hesitate to initiate new threads when/if you feel need it.


    That's what I will do
    Regards
    Ulrich
     
    roses are red, violets are blue. Some poems rhyme and some are a tiny ad:
    Gift giving made easy with the permaculture playing cards
    https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
    reply
      Bookmark Topic Watch Topic
    • New Topic