Re: slooow delete

Sebastien Bigaret <[email protected]> 11 Mar 2005 22:19:37 +0100
Newsgroups gmane.comp.python.modeling
Message-ID <[email protected]>
John Lenton <[email protected]> wrote:
> On 10 Mar 2005 15:10:59 +0100, Sebastien Bigaret
> <[email protected]> wrote:
> >=20
> > I'd like to understand why so many objects are fetched (is there, by any
> > chance, a to-many relationships without an inverse relationship defined
> > pointing back to the object?)
>=20
> I'm pretty certain there isn't; this is the entity I'm deleting (sans
> the non-relationship properties):

Just to be clear: I did not meant that having such a relationship
(without an inverse defined) is a bad thing, I was just thinking loudly
about the reason why so much objects were fetched... but I did not think
about the (now) obvious reasons:

>=20
>     Entity ('Task',
>             properties=3D [
>                 RToOne ('need', 'Need', joinSemantic=3D2, inverse=3D'task=
s'),
>                 RToOne ('team', 'Team', joinSemantic=3D2, inverse=3D'task=
s'),
>                 RToOne ('mealType', 'MealType', joinSemantic=3D2,
> inverse=3D'tasks'),
>             ],
>     ),
>=20
> the weird thing is that the entities it loads are all Tasks, the same
> thing (a whole load of Tasks getting loaded) happens upon insert; what
> triggers it in that case is
>=20
>     team.addToTasks(task)
>=20
> whereas on the previous line I have a
>=20
>     need.addToTasks(task)
>=20
> and that doesn't trigger it.


Okay: when addToTasks() is called:

1. the to-many fault is triggered, fetching all related objects and
   populating the corresponding list, here 'self._tasks' probably,

2. the new task is added to the list.

The fact that need.addToTasks(task) does not trigger any fetch simply
means that the to-many faults is already cleared --or that it also
triggers the fetch but you do not notice it since that 'need' object
does not have (many) tasks assigned.


Back to your problem in ec.delete(task): when ec.processRecentChanges()
is called, it examines your object's relationships: 'need', 'team' and
'mealType', all three being of type DELETE_NULLIFY.

  So: at processRecentChanges() time the ec takes care of the deletion
  policy. For that purpose, in this case it gets these 3 related
  objects: need, team and mealType (using KeyValueCoding) and removes
  the deleted object 'task' from their tasks... but when it does that,
  *it triggers all three to-many faults*: need.tasks, team.tasks and
  mealType.tasks... and I suspect that at least one of them is quite
  big.

  Now we know why we have 1 deleted object, 3 updated ones (the related
  need, team and mealType), and a bunch of fetched Tasks in the ec after
  processRecentChanges().


And your next question will probably be: okay, and how to change that
behaviour?  Here is a description of what should be a definitive
solution, and then a workaround you may use till that solution is
implemented.

  Changing the default baheviour requires that ec.processRecentChanges()
  becomes smarter: it should be changed so that it detects that the
  related objects 'need', 'team' and 'mealType' do not need to be
  fetched if they are not cached yet, or that their to-many faults
  'tasks' should not be cleared if they hasn't been yet (including: in
  an other EC), because simply deleting the object removes the only
  information where both the relationship and its inverse is stored: the
  Foreign Key stored in the deleted object tasks's DB-row pointing to
  resp. tables NEED, TEAM and MEAL_TYPE. [1]

I probably won't have the time for this in the coming weeks; I'm
currently overwhelmed by work and (luckily!) personal activities.

In the mean time you can bypass that behaviour by removing the related
objects:

            task.setNeed(None)
            task.setTeam(None)
            task.setMealType(None)
            ec.delete(task)
            ec.saveChanges()

Note: if, for example, the related 'team' object is the only one that
      has a big bunch of 'Tasks in stored in its inverse relationship,
      you can simply setTeam(None) and leave the other objects be
      fetched and updated by the default behaviour.  I'm saying this
      because there is a=20


*Big fat warning* (!): do that if you're absolutely sure that the
    related 'need', 'team' and 'mealType' objects are not already
    fetched in other ECs, *or*, if they are fetched, that the "inverse"
    tomany faults are not cleared.

    Respectively, check that (for 'need', same for 'team' and
    'mealType'):

      db=3Dec.rootObjectStore().objectStoreForObject(task).database()

      task_need_gID=3Dtask.getNeed().globalID()
      db.snapshotForGlobalID(task_need_gID=3Dtask) # None if unfetched yet

    and if it's not None:

      db.snapshotForSourceGlobalID(task_need_gID, 'tasks')  # should be ()


    Otherwise you may experience weird side-effects on the corresponding
    objects already fetched in other ECs, esp. when saving them (no
    pb. if you use a single EC in the app., however).


Hopefully this will help.

-- S=E9bastien.



[1] some further notes about the internals you can safely ignore (I'll
    use this post when working on the problem later): to be precise,
    propagateDeleteForObject() should be changed here.  And the
    Database's cache should also be changed accordingly, esp. in case
    where the related objects are already fetched and the corresponding
    to-many faults are already cleared.  Plus, when notification of
    changes is implemented, notification of changes for related objects
    should be posted as well (even if the objects are not actually
    fetched nor their tomany faults cleared for efficiency
    reasons)--this implies that EntityClassDescription's method
    propagateDeleteForObject() has a mean to communicate that
    information back to the EC for use at the end of the saveChanges()
    process when notifications are broadcasted)

>=20
> Here are the Relationships defined in both Need and Team:
>=20
>     Entity ('Team',
>             properties=3D [
>                 RToOne ('offer', 'Offer', joinSemantic=3D2, inverse=3D'te=
ams'),
>                 RToMany ('tasks', 'Task', inverse=3D'team'),
>                 RToMany ('userTeams', 'UserTeam', inverse=3D'team'),
>             ],
>     ),
>     Entity ('Need',
>             properties=3D [
>                 RToOne ('category', 'Category', joinSemantic=3D2,
> inverse=3D'needs'),
>                 RToOne ('sponsor', 'User', joinSemantic=3D2, inverse=3D'n=
eeders'),
>                 RToOne ('offer', 'Offer', joinSemantic=3D2, inverse=3D'ne=
eds'),
>                 RToOne ('user', 'User', joinSemantic=3D2, inverse=3D'need=
s'),
>                 RToOne ('visibility', 'Visibility', joinSemantic=3D2,
> inverse=3D'needs'),
>                 RToMany ('tasks', 'Task', inverse=3D'need'),
>             ],
>     ),
>=20
>=20
> --=20
> John Lenton ([email protected]) -- Random fortune:
> Don't anthropomorphise computers and cars, They hate that.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click