Hi all,
I spent quite some time to get used to Gemstone now . Somehow I stumble across some questions and insecurities again and again. I wonder if somebody can give me some hints on this. I use Gemstone/Web without Seaside but with a ZincREST interface. Some of my data model objects a transfered via JSON or CSV betwenn db and client. Everytime the client wants to modify data on the server he sends a JSON representation of the object to the server and the server parses the json and creates a data model object from it. Now I do have a persited version of my model object and the just newly created model object within the DB. How would I update now? I can't replace the persisted object by the new one, because I might loose references to/from it... I will need to walk through all attributes compare them and replace just different ones?! I feel like the whole approache is wrong and slow, isn't it? Wouldn't it be better to just parse the request's json into a JSONObject and do the synching after I located the persisted Object based on some hash values or id provided? How do your strategies look like? I currently feel like producing too many temporary and unneeded objects. Creade, Delete and Replace do not really provide such "imagination" issues like the Update... do they? Any push into the right direction is highly appreciated! Thanks and have fun at FAST if you'll be there! Sebastian _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
Hi Sebastian,
I’ll describe the general approach I’ve seen and taken. If you are going to have an external reference to any of your objects then you need to give the external system a unique identifier for the object(s). In our bug tracking system we give each one a bug number. When we pass some information to an external system (the user’s client browser), we embed the ID as a hidden field in the HTML form. When the form is submitted we do a lookup based on the unique ID and update the object as requested. The same should apply to JSON or CSV. I would have a class-side method (for example) that could do the lookup of the object (or create a new one if not found) based on the passed-in data and then have an instance-side method that updates the object based on the passed-in data. One complicating factor relates to a possible race condition between two clients updating the same object. To address this problem you would store a timestamp with each object and pass the timestamp with the object ID to the client. When the client returns the edit/update you check the timestamp to ensure that there has not been another edit. To avoid unnecessary edits, I typically check for changes in the setter method. That is, if a string is provided that is equivalent to the existing value, then I don’t do the update (since that would unnecessarily change the underlying object). So, yes, you are right. You should parse enough of the JSON to find the object (or create it if not present), and then update the original object from the JSON. James > On Oct 29, 2014, at 9:23 AM, Sebastian Heidbrink via Glass <[hidden email]> wrote: > > Hi all, > > I spent quite some time to get used to Gemstone now . Somehow I stumble across some questions and insecurities again and again. > > I wonder if somebody can give me some hints on this. > > I use Gemstone/Web without Seaside but with a ZincREST interface. Some of my data model objects a transfered via JSON or CSV betwenn db and client. Everytime the client wants to modify data on the server he sends a JSON representation of the object to the server and the server parses the json and creates a data model object from it. > Now I do have a persited version of my model object and the just newly created model object within the DB. > How would I update now? I can't replace the persisted object by the new one, because I might loose references to/from it... I will need to walk through all attributes compare them and replace just different ones?! > I feel like the whole approache is wrong and slow, isn't it? Wouldn't it be better to just parse the request's json into a JSONObject and do the synching after I located the persisted Object based on some hash values or id provided? > > How do your strategies look like? I currently feel like producing too many temporary and unneeded objects. > > Creade, Delete and Replace do not really provide such "imagination" issues like the Update... do they? > > Any push into the right direction is highly appreciated! > Thanks and have fun at FAST if you'll be there! > Sebastian > _______________________________________________ > Glass mailing list > [hidden email] > http://lists.gemtalksystems.com/mailman/listinfo/glass _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by GLASS mailing list
Hi all, I spent quite some time to get used to Gemstone now . Somehow I stumble across some questions and insecurities again and again. I wonder if somebody can give me some hints on this. I use Gemstone/Web without Seaside but with a ZincREST interface. Some of my data model objects a transfered via JSON or CSV betwenn db and client. Everytime the client wants to modify data on the server he sends a JSON representation of the object to the server and the server parses the json and creates a data model object from it. Now I do have a persited version of my model object and the just newly created model object within the DB. How would I update now? I can't replace the persisted object by the new one, because I might loose references to/from it... I will need to walk through all attributes compare them and replace just different ones?! I feel like the whole approache is wrong and slow, isn't it? Wouldn't it be better to just parse the request's json into a JSONObject and do the synching after I located the persisted Object based on some hash values or id provided? How do your strategies look like? I currently feel like producing too many temporary and unneeded objects. Creade, Delete and Replace do not really provide such "imagination" issues like the Update... do they? Any push into the right direction is highly appreciated! Thanks and have fun at FAST if you'll be there! Sebastian _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by GLASS mailing list
Hi Sebastian, If you replicate state between different memory spaces, you have the same kind of issues to deal with that GBS faces. There *are* a lot of complexities in the general case.On Wed, Oct 29, 2014 at 9:23 AM, Sebastian Heidbrink via Glass <[hidden email]> wrote: Hi all, _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by GLASS mailing list
Sebastian, With tODE I've taken the approach to build a thin client where the updates to server objects are done by essentially making RPC calls using blocks and STON .... If I were to map this to an web client, I would concoct a JSON packet that referenced various server-side blocks and pass the arguments to the blocks using JSON to serialize the arguments ... Then instead of passing "copies" around, you would basically be sending update messages "directly" to the objects on the server, so you'd only update the fields that were intended to be updated ... It's basically a form of the Seaside-style of associating continuation evaluation with a link on a web page, but using a block instead of a continuation ... Dale On Wed, Oct 29, 2014 at 9:23 AM, Sebastian Heidbrink via Glass <[hidden email]> wrote: Hi all, _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by GLASS mailing list
Sebastian as you are not using seaside, you should read thru and understand the part on object locking. So for example on an incoming request I take my handy unique identifier from the client, look it up, if found it's an update so I do basicDataChangedWithLock: fields "WASessionLockNotAcquiredException when signalled will cause the initial HTTP request to be retried after an abortTransaction" System writeLock: self ifDenied: [ WARetryHttpRequest signal: 'SerialNumber lock denied'. "does not return" ] ifChanged: [ System addToCommitOrAbortReleaseLocksSet: self. WARetryHttpRequest signal: 'SerialNumber lock changed'. "does not return" ]. self basicDataChanged: fields. System addToCommitOrAbortReleaseLocksSet: self. The basicDataChanged: then takes the dictionary of key/value pairs and compares against the current data. Given I work with items such as the name of the iOS device I make heavy use of symbols to store that information. Other issues are relate to the backup, for that I have this script, which I think needs some work as it sometimes hangs in the while loop if a GemTools session is active. Also because I only have a few 10 of millions of objects I can do the "SystemRepository Audit" This also then pushes the current backup to Amazon S3 which archives it after a week to Glacier. Not shown is another script that takes the output log file and builds a JIRA entry so in the morning I can jump over to JIRA and confirm the backup worked as expected. Note the s3cmd also does a PGP encryption on the data before sending, the --server-side-encryption is redundant but there out of habit. Note once a year or so the object audit reports an issue with a few objects, but running the audit again after taking the database out of production along with a page audit shows no issue. I was told it could be a transit issue. /opt/gemstone/product/bin/topaz -l -T 50000 << EOF set gemstone seaside set username DataCurator login swordfish output push backup.out errorCount run System waitForVoteStateIdle. [ System _deadNotReclaimedCount > 0 ] whileTrue: [ System sleep: 1. System abortTransaction ]. % send SystemRepository objectAudit send SystemRepository startNewLog run SystemRepository fullBackupCompressedTo: '/opt/gemstone/backups/backup-' , (DateTime now asSeconds // 60) printString. % logout errorCount exit EOF # cleanup backups cat backup.out >> backupAll.out cd /opt/gemstone/backups ls -l find . -maxdepth 1 -daystart -mtime -1 -type f -exec /usr/local/bin/s3cmd --server-side-encryption --reduced-redundancy -e put {} s3://foobartoobar \; # (ls -t backup* | head -n 2; ls backup*) | sort | uniq -u | xargs rm if [ "2" -le "`find . -mtime -2 -name 'backup*' | wc -l`" ]; then cd /opt/gemstone/product/seaside/data find . -maxdepth 1 -mtime +2 -name 'tranlog*' -exec rm {} \; fi On Wed, Oct 29, 2014 at 9:40 AM, Richard Sargent via Glass <[hidden email]> wrote:
===========================================================================
John M. McIntosh <[hidden email]> https://www.linkedin.com/in/smalltalk =========================================================================== _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
Hi John, James, Dale and Richard,
thank you so much for the vast amount of information. @Dale The tODE approche is tempting and I will definitely consider it for a part of my project. I assume it is not the perfect way for an interface that should also aloow access to non smalltalk cilents. I also guess that security related implementations might become too dfficult once one would allow the block based protocol. ('(Smalltalk exceptTheStuffINeedToCommit) become: nil') ;-) @John Thank you! I never saw somebody using the writeLock: mechanism. I assume that this is THE MOST CONFILCT PROHIBITIVE WAY to do things. I assume this will prevent you from headaches once you work with several gems... I might consider using this approach combined with James idea Thank you also for the insight to your backup script. @James That sounds interesting. I never thought about that. I assume that approach is only used on non collection based attributes. @Richard Well, this is something I have in mind for some parts of my tool, but yet it is still beyond my experience when it might make sense to have such mechanism or not. I think I need to start small and let first usecases decide where it is needed or not ;-) Thanks to John I came accross the old Seaside Examples like the Sushi Store! I'll analyze implementations in there, too. So I will do my research based on your thoughts and try to find a way to wrap my brain around it :-D All the Best Sebastian Am 29.10.2014 10:22, schrieb John McIntosh:
_______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
> On Oct 29, 2014, at 1:33 PM, Sebastian Heidbrink via Glass <[hidden email]> wrote:
> > @James > That sounds interesting. I never thought about that. I assume that approach is only used on non collection based attributes. Depending on how complex you want to make the “foreign” system, you can use the same approach. In addition to giving your root object a unique ID you can give a unique ID to any other persistent objects and then add/remove them from a collection. The extreme case would be to use the OOP/OID from GemStone as the unique ID and then create message sends remotely. Your JSON could be as sophisticated/trivial as: { “receiver”: { “id”: 123 }, “selector”: “addAll:”, “arguments”: [ { “id”: 456 }, { “id”: 789 } ] } In addition to using object identifiers, you could provide string literals, numeric literals, booleans, etc. James _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
James,
> The extreme case would be to use the OOP/OID from GemStone as the unique ID I have a similar case in my application. Some GemStone object are updated from a Relational Database (MySQL). * Once an Object has an OOP it will remain the same until the Object is garbage collected ? * Or the OOP of an object can change during it's life time ? In my app each Relational Row is mapped to a Dictionary, and the Object it self is never changed but it's instance variables are constantly updated with relational data. If i use the OOP as way to map object with external system we MUST be sure that the OPP is allways the same... Regards, Bruno |
Bruno, If you are using the oop of an object as an id that is shared with other systems you have to take some care:places persistent. Other vms in the system will not be able to access the temporary objects in the oops of temp objects, you almost certainly have to use an "export set" to keep them alive. On Thu, Oct 30, 2014 at 11:45 AM, BrunoBB via Glass <[hidden email]> wrote: James, _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
In reply to this post by BrunoBB
Dale has given a good overview of the rules for using an OOP. I would add a disclaimer. Officially, we consider the OOP to be internal. In our own tools (GemBuilder for Smalltalk, etc.) we rely on the OOP remaining the same during the life of an individual Gem, and based on the GCI library architecture, design, and documentation this is guaranteed. We do, however, reserve the right to change an object’s OOP at other times and have done so at least once—at the migration from 32-bit to 64-bit.
Thus, using an OOP to interact with a user client during the life of a login session is safe as long as you understand the design Dale described (especially the export set). Storing an OOP in a foreign system would be moving beyond our internal use and would be slightly more risky. It is a small risk, but there are no guarantees beyond the life of the Gem that retrieved the object and obtained its OOP. James > On Oct 30, 2014, at 11:45 AM, BrunoBB via Glass <[hidden email]> wrote: > > James, > >> The extreme case would be to use the OOP/OID from GemStone as the unique >> ID > > I have a similar case in my application. Some GemStone object are updated > from a Relational Database (MySQL). > > * Once an Object has an OOP it will remain the same until the Object is > garbage collected ? > * Or the OOP of an object can change during it's life time ? > > In my app each Relational Row is mapped to a Dictionary, and the Object it > self is never changed but it's instance variables are constantly updated > with relational data. > > If i use the OOP as way to map object with external system we MUST be sure > that the OPP is allways the same... > > Regards, > Bruno > > > > > -- > View this message in context: http://forum.world.st/Glass-how-to-update-models-properly-tp4787473p4787663.html > Sent from the GLASS mailing list archive at Nabble.com. > _______________________________________________ > Glass mailing list > [hidden email] > http://lists.gemtalksystems.com/mailman/listinfo/glass _______________________________________________ Glass mailing list [hidden email] http://lists.gemtalksystems.com/mailman/listinfo/glass |
Dale, James,
Thanks for your answer very useful. Especifically in my case the use of an OOP is done in a very short time: * The GemStone/S Seaside app has a link to a Java Form. * The user click on the Smalltalk object and goes to Java Form (in the url parameter we pass a GUID to the Java app) * The Java app callback a Gs Rest Service and pass the GUID again to GS. * The GS app answer an XML (including the OOP of the clicked object) that is displayed in a Java form. * The user take his time to fill the Java form.... finally clicks "Send Form" * The Java app do a POST to a GemStone Rest Service with the XML of the filled form (including the OOP) * Finally: myObject := Object _objectForOop: (Integer fromString: stringOOPfromJava). "the map between the Java object and the Smalltalk object" Regards, Bruno |
Free forum by Nabble | Edit this page |