server/sources/native.py
changeset 6931 0af44a38fe41
parent 6882 b5e34836f84e
parent 6889 37668bf302f5
child 6945 28bf94d062a9
--- a/server/sources/native.py	Mon Jan 24 19:09:42 2011 +0100
+++ b/server/sources/native.py	Tue Feb 01 11:52:10 2011 +0100
@@ -35,6 +35,7 @@
 from contextlib import contextmanager
 from os.path import abspath
 import re
+import itertools
 
 from logilab.common.compat import any
 from logilab.common.cache import Cache
@@ -553,23 +554,29 @@
         #    on the filesystem. To make the entity.data usage absolutely
         #    transparent, we'll have to reset entity.data to its binary
         #    value once the SQL query will be executed
-        restore_values = {}
-        etype = entity.__regid__
+        restore_values = []
+        if isinstance(entity, list):
+            entities = entity
+        else:
+            entities = [entity]
+        etype = entities[0].__regid__
         for attr, storage in self._storages.get(etype, {}).items():
-            try:
-                edited = entity.cw_edited
-            except AttributeError:
-                assert event == 'deleted'
-                getattr(storage, 'entity_deleted')(entity, attr)
-            else:
-                if attr in edited:
-                    handler = getattr(storage, 'entity_%s' % event)
-                    restore_values[attr] = handler(entity, attr)
+            for entity in entities:
+                try:
+                    edited = entity.cw_edited
+                except AttributeError:
+                    assert event == 'deleted'
+                    getattr(storage, 'entity_deleted')(entity, attr)
+                else:
+                    if attr in edited:
+                        handler = getattr(storage, 'entity_%s' % event)
+                        to_restore = handler(entity, attr)
+                        restore_values.append((entity, attr, to_restore))
         try:
             yield # 2/ execute the source's instructions
         finally:
             # 3/ restore original values
-            for attr, value in restore_values.items():
+            for entity, attr, value in restore_values:
                 entity.cw_edited.edited_attribute(attr, value)
 
     def add_entity(self, session, entity):
@@ -923,7 +930,7 @@
         * transfer it to the deleted_entities table if the entity's type is
           multi-sources
         """
-        self.fti_unindex_entity(session, entity.eid)
+        self.fti_unindex_entities(session, [entity])
         attrs = {'eid': entity.eid}
         self.doexec(session, self.sqlgen.delete('entities', attrs), attrs)
         if not entity.__regid__ in self.multisources_etypes:
@@ -935,6 +942,27 @@
                  'source': uri, 'dtime': datetime.now()}
         self.doexec(session, self.sqlgen.insert('deleted_entities', attrs), attrs)
 
+    def delete_info_multi(self, session, entities, uri, extids):
+        """delete system information on deletion of an entity:
+        * update the fti
+        * remove record from the entities table
+        * transfer it to the deleted_entities table if the entity's type is
+          multi-sources
+        """
+        self.fti_unindex_entities(session, entities)
+        attrs = {'eid': '(%s)' % ','.join([str(_e.eid) for _e in entities])}
+        self.doexec(session, self.sqlgen.delete_many('entities', attrs), attrs)
+        if entities[0].__regid__ not in self.multisources_etypes:
+            return
+        attrs = {'type': entities[0].__regid__,
+                 'source': uri, 'dtime': datetime.now()}
+        for entity, extid in itertools.izip(entities, extids):
+            if extid is not None:
+                assert isinstance(extid, str), type(extid)
+                extid = b64encode(extid)
+            attrs.update({'eid': entity.eid, 'extid': extid})
+            self.doexec(session, self.sqlgen.insert('deleted_entities', attrs), attrs)
+
     def modified_entities(self, session, etypes, mtime):
         """return a 2-uple:
         * list of (etype, eid) of entities of the given types which have been
@@ -1302,27 +1330,32 @@
         """
         FTIndexEntityOp.get_instance(session).add_data(entity.eid)
 
-    def fti_unindex_entity(self, session, eid):
-        """remove text content for entity with the given eid from the full text
-        index
+    def fti_unindex_entities(self, session, entities):
+        """remove text content for entities from the full text index
         """
+        cursor = session.pool['system']
+        cursor_unindex_object = self.dbhelper.cursor_unindex_object
         try:
-            self.dbhelper.cursor_unindex_object(eid, session.pool['system'])
+            for entity in entities:
+                cursor_unindex_object(entity.eid, cursor)
         except Exception: # let KeyboardInterrupt / SystemExit propagate
-            self.exception('error while unindexing %s', eid)
+            self.exception('error while unindexing %s', entity)
+
 
-    def fti_index_entity(self, session, entity):
-        """add text content of a created/modified entity to the full text index
+    def fti_index_entities(self, session, entities):
+        """add text content of created/modified entities to the full text index
         """
-        self.debug('reindexing %r', entity.eid)
+        cursor_index_object = self.dbhelper.cursor_index_object
+        cursor = session.pool['system']
         try:
             # use cursor_index_object, not cursor_reindex_object since
             # unindexing done in the FTIndexEntityOp
-            self.dbhelper.cursor_index_object(entity.eid,
-                                              entity.cw_adapt_to('IFTIndexable'),
-                                              session.pool['system'])
+            for entity in entities:
+                cursor_index_object(entity.eid,
+                                    entity.cw_adapt_to('IFTIndexable'),
+                                    cursor)
         except Exception: # let KeyboardInterrupt / SystemExit propagate
-            self.exception('error while reindexing %s', entity)
+            self.exception('error while indexing %s', entity)
 
 
 class FTIndexEntityOp(hook.DataOperationMixIn, hook.LateOperation):
@@ -1338,17 +1371,17 @@
         source = session.repo.system_source
         pendingeids = session.transaction_data.get('pendingeids', ())
         done = session.transaction_data.setdefault('indexedeids', set())
+        to_reindex = set()
         for eid in self.get_data():
             if eid in pendingeids or eid in done:
                 # entity added and deleted in the same transaction or already
                 # processed
-                return
+                continue
             done.add(eid)
             iftindexable = session.entity_from_eid(eid).cw_adapt_to('IFTIndexable')
-            for container in iftindexable.fti_containers():
-                source.fti_unindex_entity(session, container.eid)
-                source.fti_index_entity(session, container)
-
+            to_reindex |= set(iftindexable.fti_containers())
+        source.fti_unindex_entities(session, to_reindex)
+        source.fti_index_entities(session, to_reindex)
 
 def sql_schema(driver):
     helper = get_db_helper(driver)