Use a moved_entities table to record external entities moved to the system source
authorJulien Cristau <julien.cristau@logilab.fr>
Fri, 16 Jan 2015 12:35:46 +0100
changeset 10209 4c64a41c0a1d
parent 10208 249126034c0e
child 10210 633d85ba9f72
Use a moved_entities table to record external entities moved to the system source Instead of using a negative eid in the entities table, move the record to a new table so we don't have an interval with a missing eid in entities. Related to #4846892
hooks/metadata.py
misc/migration/3.21.0_Any.py
server/sources/native.py
--- a/hooks/metadata.py	Fri Jan 16 12:43:32 2015 +0100
+++ b/hooks/metadata.py	Fri Jan 16 12:35:46 2015 +0100
@@ -199,17 +199,15 @@
             oldsource = self._cw.entity_from_eid(schange[self.eidfrom])
             entity = self._cw.entity_from_eid(self.eidfrom)
             # we don't want the moved entity to be reimported later.  To
-            # distinguish this state, the trick is to change the associated
-            # record in the 'entities' system table with eid=-eid while leaving
-            # other fields unchanged, and to add a new record with eid=eid,
-            # source='system'. External source will then have consider case
-            # where `extid2eid` return a negative eid as 'this entity was known
-            # but has been moved, ignore it'.
-            self._cw.system_sql('UPDATE entities SET eid=-eid WHERE eid=%(eid)s',
-                                {'eid': self.eidfrom})
+            # distinguish this state, move the record from the 'entities' table
+            # to 'moved_entities'.  External source will then have consider
+            # case where `extid2eid` returns a negative eid as 'this entity was
+            # known but has been moved, ignore it'.
+            attrs = {'eid': entity.eid, 'extid': self._cw.entity_metas(entity.eid)['extid']}
+            self._cw.system_sql(syssource.sqlgen.insert('moved_entities', attrs), attrs)
             attrs = {'type': entity.cw_etype, 'eid': entity.eid, 'extid': None,
                      'asource': 'system'}
-            self._cw.system_sql(syssource.sqlgen.insert('entities', attrs), attrs)
+            self._cw.system_sql(syssource.sqlgen.update('entities', attrs, ['eid']), attrs)
             # register an operation to update repository/sources caches
             ChangeEntitySourceUpdateCaches(self._cw, entity=entity,
                                            oldsource=oldsource.repo_source,
--- a/misc/migration/3.21.0_Any.py	Fri Jan 16 12:43:32 2015 +0100
+++ b/misc/migration/3.21.0_Any.py	Fri Jan 16 12:35:46 2015 +0100
@@ -2,4 +2,18 @@
 helper = repo.system_source.dbhelper
 sql('DROP INDEX entities_extid_idx')
 sql(helper.sql_create_index('entities', 'extid', True))
+
+sql('''
+CREATE TABLE moved_entities (
+  eid INTEGER PRIMARY KEY NOT NULL,
+  extid VARCHAR(256) UNIQUE
+)
+''')
+
+moved_entities = sql('SELECT -eid, extid FROM entities WHERE eid < 0')
+cu = session.cnxset.cu
+cu.executemany('INSERT INTO moved_entities (eid, extid) VALUES (%s, %s)',
+               moved_entities)
+sql('DELETE FROM entities WHERE eid < 0')
+
 commit()
--- a/server/sources/native.py	Fri Jan 16 12:43:32 2015 +0100
+++ b/server/sources/native.py	Fri Jan 16 12:35:46 2015 +0100
@@ -868,9 +868,10 @@
     def extid2eid(self, cnx, extid):
         """get eid from an external id. Return None if no record found."""
         assert isinstance(extid, str)
+        args = {'x': b64encode(extid)}
         cursor = self.doexec(cnx,
                              'SELECT eid FROM entities WHERE extid=%(x)s',
-                             {'x': b64encode(extid)})
+                             args)
         # XXX testing rowcount cause strange bug with sqlite, results are there
         #     but rowcount is 0
         #if cursor.rowcount > 0:
@@ -880,6 +881,17 @@
                 return result[0]
         except Exception:
             pass
+        cursor = self.doexec(cnx,
+                             'SELECT eid FROM moved_entities WHERE extid=%(x)s',
+                             args)
+        try:
+            result = cursor.fetchone()
+            if result:
+                # entity was moved to the system source, return negative
+                # number to tell the external source to ignore it
+                return -result[0]
+        except Exception:
+            pass
         return None
 
     def _handle_is_relation_sql(self, cnx, sql, attrs):
@@ -1390,6 +1402,10 @@
   extid VARCHAR(256) UNIQUE
 );;
 CREATE INDEX entities_type_idx ON entities(type);;
+CREATE TABLE moved_entities (
+  eid INTEGER PRIMARY KEY NOT NULL,
+  extid VARCHAR(256) UNIQUE
+);;
 
 CREATE TABLE transactions (
   tx_uuid CHAR(32) PRIMARY KEY NOT NULL,