Discussion:
[Modeling-users] saveChanges() doesn't change globalID
Marcos Dione
2004-09-08 20:13:24 UTC
Permalink
User-Agent: Mutt/1.3.28i


hi all. I'm experimenting since a few months w/ building a rollback
scheme above modeling. the problems I found were this:

given a EditingContext, there a re two kind of objects registered at
the moment fo saveChanges(): from-database ones (globalID() is an
instance of KeyGlobalID), and new ones (globalID() is an instance of
TemporaryGlobalID). when I roll back, I do the following:

* 'hold' the model: any from-database object gets hold by means of
snapshot_raw(). new ones are simply forgoten.

* build a new EditingContext.

* repopulate it with the old objects. from-database ones get reinserted
via faultForRaw(), and new ones simply requesting a new instance of the
proper class.

this works fine, but a probblem arises: if I create a new object,
add it to the EditingContext(), then saveChenges(), it *sometimes* gets
converted to a from-database one (which is what I would mostly spect;
see definition above) and sometimes it doesn't (which would not be so
bad if it wouldn't be just 'sometimes'). keep in mind that now I'm just
playing with only one entity, so it doesn't seem to be an entity
problem, if you know what I mean.

is this possible (the sometimes part), could it be a bug in
Modeling, or I'm just getting lucky sometimes? which would be the
spected behaviour? if you need some code I can post it tomorrow.

TIA.
Sebastien Bigaret
2004-09-09 08:46:37 UTC
Permalink
Hi,
Post by Marcos Dione
hi all. I'm experimenting since a few months w/ building a rollback
given a EditingContext, there a re two kind of objects registered at
the moment fo saveChanges(): from-database ones (globalID() is an
instance of KeyGlobalID), and new ones (globalID() is an instance of
* 'hold' the model: any from-database object gets hold by means of
snapshot_raw(). new ones are simply forgoten.
* build a new EditingContext.
* repopulate it with the old objects. from-database ones get reinserted
via faultForRaw(), and new ones simply requesting a new instance of the
proper class.
Could you be a little more explicit about the use cases behind this
rollback mechanism? Are "from-db objects" changed within the EC? Or do
you simply want to remove the inserted ones, and to revert the
persistent ones to the state they have in the db? Or...?

Plus, when you say you repopulate the new EC with the new ones, how is
this done?

(just asking all this to learn a bit more about your context)
Post by Marcos Dione
this works fine, but a probblem arises: if I create a new object,
add it to the EditingContext(), then saveChenges(), it *sometimes* gets
converted to a from-database one (which is what I would mostly spect;
see definition above) and sometimes it doesn't (which would not be so
bad if it wouldn't be just 'sometimes'). keep in mind that now I'm just
playing with only one entity, so it doesn't seem to be an entity
problem, if you know what I mean.
is this possible (the sometimes part), could it be a bug in
Modeling, or I'm just getting lucky sometimes? which would be the
spected behaviour? if you need some code I can post it tomorrow.
I really need some code here, I'm not positively sure to see what the
problem is. What I understand follows.

If what you see is newly inserted objects not getting their
corresponding KeyGlobalID after ec.saveChanges(), but keeping their
old TemporaryGlobalID instead, this is definitely a bug, and a serious
one, and I'm very interesting in seeing the code triggering it.

More details in case you're interested and you want to investigate
this: changing newly inserted objects gIDs is done at the very end of
the saveChanges() process, and DBContext.finalizeCommitChanges() is
responsible for this. It broadcasts a GlobalIDChangedNotification,
handled by ec.handleNotification() (among other possible observers)
which in turn re-registers the object with its newly assigned
KeyGlobalID.


-- Sébastien.
Marcos Dione
2004-09-09 17:10:10 UTC
Permalink
User-Agent: Mutt/1.3.28i
Post by Sebastien Bigaret
Post by Marcos Dione
given a EditingContext, there a re two kind of objects registered at
the moment fo saveChanges(): from-database ones (globalID() is an
instance of KeyGlobalID), and new ones (globalID() is an instance of
* 'hold' the model: any from-database object gets hold by means of
snapshot_raw(). new ones are simply forgoten.
* build a new EditingContext.
* repopulate it with the old objects. from-database ones get reinserted
via faultForRaw(), and new ones simply requesting a new instance of the
proper class.
Could you be a little more explicit about the use cases behind this
rollback mechanism?
I'll try :) the general idea is to be able to get the previous state
of any object inserted in the ec. this previous state for from-db
instances is the state in the db, that's why I foult them and then let
Modeling refetch the values on any reference to any of its attributes.
for new ones, it would be an empty model, like the one get w/ just
calling the proper constructor. e.g., say I have a Persona entity, an
empty model is the result of calling Persona().
Post by Sebastien Bigaret
Are "from-db objects" changed within the EC?
could be. a rollback must revert their properties' values to the ones
in the db.
Post by Sebastien Bigaret
Or do
you simply want to remove the inserted ones,
as the way I sue it, you can't add several empty instances, so a
rollback after modifing it just gives me an empty model again. also, no
more that one model can be handled at the same time.

the usage of this rollbackable thing is to develop a
insert-modify-delete part of a bigger application. the user can be
handling only one instance at a time, but this instance could have
several other instances of other (or the same) related to it, and
being edited at the same time.

e.g, here we have a Persona() entity, related with several
PostalAddr(). the user can be editing only one Persona, but several
(all the related ones) PostalAddr. the rollback mechanisms throws
away the ec, and repopulates starting from the Persona, so the
rollback applies to the persona and its related objects. maybe later
we'll add support for rollbacking individual PostalAddr's.
Post by Sebastien Bigaret
and to revert the
persistent ones to the state they have in the db?
yeap.
Post by Sebastien Bigaret
Plus, when you say you repopulate the new EC with the new ones, how is
this done?
o= Persona ()
ec.insert (o)

(more or less)
Post by Sebastien Bigaret
If what you see is newly inserted objects not getting their
corresponding KeyGlobalID after ec.saveChanges(), but keeping their
old TemporaryGlobalID instead, this is definitely a bug, and a serious
one, and I'm very interesting in seeing the code triggering it.
good, this seems to be the thing happening.
Post by Sebastien Bigaret
More details in case you're interested and you want to investigate
this: changing newly inserted objects gIDs is done at the very end of
the saveChanges() process, and DBContext.finalizeCommitChanges() is
responsible for this. It broadcasts a GlobalIDChangedNotification,
handled by ec.handleNotification() (among other possible observers)
which in turn re-registers the object with its newly assigned
KeyGlobalID.
good! I'll try to see it now and post any clues later.
Sebastien Bigaret
2004-09-09 20:43:10 UTC
Permalink
Post by Marcos Dione
the usage of this rollbackable thing is to develop a
insert-modify-delete part of a bigger application. the user can be
handling only one instance at a time, but this instance could have
several other instances of other (or the same) related to it, and
being edited at the same time.
e.g, here we have a Persona() entity, related with several
PostalAddr(). the user can be editing only one Persona, but several
(all the related ones) PostalAddr. the rollback mechanisms throws
away the ec, and repopulates starting from the Persona, so the
rollback applies to the persona and its related objects. maybe later
we'll add support for rollbacking individual PostalAddr's.
Given this, and what you say about new objects (simply calling the
constructor), I wonder why you need to explicitly track the rollback
thing.

I mean, if you simply drop the existing ECs and get a brand new one,
then ask it for the Persona() (either from a given fetch qualifier or
from its globalID), and then its postal addr. with
person.getPostalAddresses(), then you instantly get what is in the db
--no need to keep raw rows under the pillow, just because an EC is in
fact a transaction at the object level: until you saveChanges(), the
changes are not persistent and there's nothing to do to retrieve the
objects as they are stored in the db.

I suspect I'm missing something important here --because if you simply
want to rollback, then you wouldn't try to (re) add newly inserted
objects (PostallAddresses I guess) from the beginning. This probably
means that you want to rollback some changes, while keeping newly
inserted objects, and maybe(?) how relationships between newly inserted
and 'from-db' objects were modified. Sorry if I did not understand you
right, again a sample code might help, showing what happens before a
rollback, and what you want to get after the custom rollback happens.
Post by Marcos Dione
Post by Sebastien Bigaret
If what you see is newly inserted objects not getting their
corresponding KeyGlobalID after ec.saveChanges(), but keeping their
old TemporaryGlobalID instead, this is definitely a bug, and a serious
one, and I'm very interesting in seeing the code triggering it.
good, this seems to be the thing happening.
Now, whatever your use-cases are and what is behind, I want to make it
clear that, if this is the bug you're observing, this is a serious one
that should be addressed as quickly as possible. If you do not have
the time to extract the behaviour but have some code revealing it that
you do not want to disclose on a public list, please email me
privately and we'll work together on making from your experience a
public test revealing the bug.

Thanks for your time!

-- Sébastien.
Post by Marcos Dione
Post by Sebastien Bigaret
Post by Marcos Dione
given a EditingContext, there a re two kind of objects registered at
the moment fo saveChanges(): from-database ones (globalID() is an
instance of KeyGlobalID), and new ones (globalID() is an instance of
* 'hold' the model: any from-database object gets hold by means of
snapshot_raw(). new ones are simply forgoten.
* build a new EditingContext.
* repopulate it with the old objects. from-database ones get reinserted
via faultForRaw(), and new ones simply requesting a new instance of the
proper class.
Could you be a little more explicit about the use cases behind this
rollback mechanism?
I'll try :) the general idea is to be able to get the previous state
of any object inserted in the ec. this previous state for from-db
instances is the state in the db, that's why I foult them and then let
Modeling refetch the values on any reference to any of its attributes.
for new ones, it would be an empty model, like the one get w/ just
calling the proper constructor. e.g., say I have a Persona entity, an
empty model is the result of calling Persona().
Post by Sebastien Bigaret
Are "from-db objects" changed within the EC?
could be. a rollback must revert their properties' values to the ones
in the db.
Post by Sebastien Bigaret
Or do
you simply want to remove the inserted ones,
as the way I sue it, you can't add several empty instances, so a
rollback after modifing it just gives me an empty model again. also, no
more that one model can be handled at the same time.
the usage of this rollbackable thing is to develop a
insert-modify-delete part of a bigger application. the user can be
handling only one instance at a time, but this instance could have
several other instances of other (or the same) related to it, and
being edited at the same time.
e.g, here we have a Persona() entity, related with several
PostalAddr(). the user can be editing only one Persona, but several
(all the related ones) PostalAddr. the rollback mechanisms throws
away the ec, and repopulates starting from the Persona, so the
rollback applies to the persona and its related objects. maybe later
we'll add support for rollbacking individual PostalAddr's.
Post by Sebastien Bigaret
and to revert the
persistent ones to the state they have in the db?
yeap.
Post by Sebastien Bigaret
Plus, when you say you repopulate the new EC with the new ones, how is
this done?
o= Persona ()
ec.insert (o)
(more or less)
Post by Sebastien Bigaret
If what you see is newly inserted objects not getting their
corresponding KeyGlobalID after ec.saveChanges(), but keeping their
old TemporaryGlobalID instead, this is definitely a bug, and a serious
one, and I'm very interesting in seeing the code triggering it.
good, this seems to be the thing happening.
Post by Sebastien Bigaret
More details in case you're interested and you want to investigate
this: changing newly inserted objects gIDs is done at the very end of
the saveChanges() process, and DBContext.finalizeCommitChanges() is
responsible for this. It broadcasts a GlobalIDChangedNotification,
handled by ec.handleNotification() (among other possible observers)
which in turn re-registers the object with its newly assigned
KeyGlobalID.
good! I'll try to see it now and post any clues later.
Marcos Dione
2004-09-11 17:32:01 UTC
Permalink
User-Agent: Mutt/1.3.28i
Post by Sebastien Bigaret
I mean, if you simply drop the existing ECs and get a brand new one,
then ask it for the Persona() (either from a given fetch qualifier or
from its globalID),
note that holding the globalID is the same that using the raw_row.
the fetch qualifier wouldn't be useful, as the user could have selected
the Persona() fron la list (the result of a search). I realize you don't
know that part of the app yet :)

anyways, the problem is not with from-db instances, but with new
instances.
Post by Sebastien Bigaret
I suspect I'm missing something important here --because if you simply
want to rollback, then you wouldn't try to (re) add newly inserted
objects (PostallAddresses I guess) from the beginning.
maybe, I haven't decided taht part, but forgetting them sounds
reasonable. for rollbacking limited instances we would prefer to obligue
the user to save the changes to a previous instance.
Post by Sebastien Bigaret
Now, whatever your use-cases are and what is behind, I want to make it
clear that, if this is the bug you're observing, this is a serious one
that should be addressed as quickly as possible. If you do not have
the time to extract the behaviour but have some code revealing it that
you do not want to disclose on a public list, please email me
privately and we'll work together on making from your experience a
public test revealing the bug.
well, I have code, but it's very buried in my app's code. unluckly I
don't have the time this weeken to try to untangle a simpler example,
and I don't know if my code's guilty. can I send you the whole bunch
(~140k)?
Post by Sebastien Bigaret
Thanks for your time!
thanks for *yours*.
Sebastien Bigaret
2004-09-11 21:38:01 UTC
Permalink
Post by Marcos Dione
User-Agent: Mutt/1.3.28i
Post by Sebastien Bigaret
I mean, if you simply drop the existing ECs and get a brand new one,
then ask it for the Persona() (either from a given fetch qualifier or
from its globalID),
note that holding the globalID is the same that using the raw_row.
Yeap! except that gIDs have the minimum amount of information needed to
retrieve objects, while raw rows can have a much bigger memory footprint ;)
Post by Marcos Dione
the fetch qualifier wouldn't be useful, as the user could have selected
the Persona() fron la list (the result of a search). I realize you don't
know that part of the app yet :)
Ok
Post by Marcos Dione
anyways, the problem is not with from-db instances, but with new
instances.
Post by Sebastien Bigaret
I suspect I'm missing something important here --because if you simply
want to rollback, then you wouldn't try to (re) add newly inserted
objects (PostallAddresses I guess) from the beginning.
maybe, I haven't decided taht part, but forgetting them sounds
reasonable. for rollbacking limited instances we would prefer to obligue
the user to save the changes to a previous instance.
Post by Sebastien Bigaret
Now, whatever your use-cases are and what is behind, I want to make it
clear that, if this is the bug you're observing, this is a serious one
that should be addressed as quickly as possible. If you do not have
the time to extract the behaviour but have some code revealing it that
you do not want to disclose on a public list, please email me
privately and we'll work together on making from your experience a
public test revealing the bug.
well, I have code, but it's very buried in my app's code. unluckly I
don't have the time this weeken to try to untangle a simpler example,
and I don't know if my code's guilty. can I send you the whole bunch
(~140k)?
If you can, sure: this would help to have the code triggering the bug at
hand --along with the instructions for reproducing and observing the
bug.

-- Sébastien.

Marcos Dione
2004-09-09 17:53:01 UTC
Permalink
User-Agent: Mutt/1.3.28i
Post by Sebastien Bigaret
More details in case you're interested and you want to investigate
this: changing newly inserted objects gIDs is done at the very end of
the saveChanges() process, and DBContext.finalizeCommitChanges() is
responsible for this. It broadcasts a GlobalIDChangedNotification,
handled by ec.handleNotification() (among other possible observers)
which in turn re-registers the object with its newly assigned
KeyGlobalID.
according to the comments in ec.handleNotification(), the PK is not
changed to a GlobalID until then, so I can assume that code isn't
reached, so maybe an exception is trown earlier. I'll try to find it
tomorrow (now I gotta run to another job).

I also saw a few debug(), warn() and trace() callings, and found
their declaration in logging.py. should I assign log_stderr to them so
they show something? I see that no_log can receive a severity param, but
log_stderr doesn't. should I fix that?
Sebastien Bigaret
2004-09-09 20:37:07 UTC
Permalink
Post by Marcos Dione
User-Agent: Mutt/1.3.28i
Post by Sebastien Bigaret
More details in case you're interested and you want to investigate
this: changing newly inserted objects gIDs is done at the very end of
the saveChanges() process, and DBContext.finalizeCommitChanges() is
responsible for this. It broadcasts a GlobalIDChangedNotification,
handled by ec.handleNotification() (among other possible observers)
which in turn re-registers the object with its newly assigned
KeyGlobalID.
according to the comments in ec.handleNotification(), the PK is not
changed to a GlobalID until then, so I can assume that code isn't
reached, so maybe an exception is trown earlier. I'll try to find it
tomorrow (now I gotta run to another job).
Okay, if you do not have much time you cannot investigate it any
deeper --but still, a portion of code exhibiting the problem (as opposed
to: diagnosing the problem) could be enough, so just send it as-is if
you have it :)
Post by Marcos Dione
I also saw a few debug(), warn() and trace() callings, and found
their declaration in logging.py. should I assign log_stderr to them so
they show something? I see that no_log can receive a severity param, but
log_stderr doesn't. should I fix that?
Nope. If you want to activate all message simply replace the line
saying:
trace=debug=info=log=warn=error=fatal=no_log
with:
trace=debug=info=log=warn=error=fatal=log_stderr

and set MDL_ENABLE_DATABASE_LOGGING to '1'.


-- Sébastien.
Loading...