Commit 9bca8e5e authored by Vincent Pelletier's avatar Vincent Pelletier

IdTool: Add poisoning support.

Allows for safe migration to another id generator, by preventing silent
success of any piece of code still using the former generator, allowing
its detection and resolution before duplicate ids are emitted.
As a consequence, also allows on-demand and partial migration of id
generators.
parent dde89f18
...@@ -81,7 +81,8 @@ class IdGenerator(Base): ...@@ -81,7 +81,8 @@ class IdGenerator(Base):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewIdList') 'generateNewIdList')
def generateNewIdList(self, id_group=None, id_count=1, default=None): def generateNewIdList(self, id_group=None, id_count=1, default=None,
poison=False):
""" """
Generate a list of next ids in the sequence of ids of a particular group Generate a list of next ids in the sequence of ids of a particular group
Store the last id on a database in the portal_ids table Store the last id on a database in the portal_ids table
...@@ -94,7 +95,8 @@ class IdGenerator(Base): ...@@ -94,7 +95,8 @@ class IdGenerator(Base):
raise TypeError, 'id_group is not a string' raise TypeError, 'id_group is not a string'
return self._getLatestSpecialiseValue().generateNewIdList(id_group=id_group, return self._getLatestSpecialiseValue().generateNewIdList(id_group=id_group,
id_count=id_count, id_count=id_count,
default=default) default=default,
poison=poison)
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'initializeGenerator') 'initializeGenerator')
......
...@@ -58,7 +58,7 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator): ...@@ -58,7 +58,7 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator):
last_max_id_dict = None last_max_id_dict = None
def _generateNewId(self, id_group, id_count=1, default=None): def _generateNewId(self, id_group, id_count=1, default=None, poison=False):
""" """
Return the next_id with the last_id with the sql method Return the next_id with the last_id with the sql method
Store the last id on a database in the portal_ids table Store the last id on a database in the portal_ids table
...@@ -92,6 +92,8 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator): ...@@ -92,6 +92,8 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator):
try: try:
# Tries of generate the new_id # Tries of generate the new_id
new_id = result_query[0]['LAST_INSERT_ID()'] new_id = result_query[0]['LAST_INSERT_ID()']
if poison:
portal.IdTool_zSetLastId(id_group, None)
# Commit the changement of new_id # Commit the changement of new_id
portal.IdTool_zCommit() portal.IdTool_zCommit()
except ProgrammingError, error: except ProgrammingError, error:
...@@ -114,6 +116,8 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator): ...@@ -114,6 +116,8 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator):
# Check the store interval to store the data # Check the store interval to store the data
if last_max_id_value <= new_id - (self.getStoreInterval() or 1): if last_max_id_value <= new_id - (self.getStoreInterval() or 1):
last_max_id.set(new_id) last_max_id.set(new_id)
if poison:
last_max_id.set(None)
return new_id return new_id
def _updateSqlTable(self): def _updateSqlTable(self):
...@@ -141,20 +145,20 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator): ...@@ -141,20 +145,20 @@ class SQLNonContinuousIncreasingIdGenerator(IdGenerator):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewId') 'generateNewId')
def generateNewId(self, id_group=None, default=None): def generateNewId(self, id_group=None, default=None, poison=False):
""" """
Generate the next id in the sequence of ids of a particular group Generate the next id in the sequence of ids of a particular group
""" """
return self._generateNewId(id_group=id_group, default=default) return self._generateNewId(id_group=id_group, default=default, poison=poison)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewIdList') 'generateNewIdList')
def generateNewIdList(self, id_group=None, id_count=1, default=None): def generateNewIdList(self, id_group=None, id_count=1, default=None, poison=False):
""" """
Generate a list of next ids in the sequence of ids of a particular group Generate a list of next ids in the sequence of ids of a particular group
""" """
new_id = 1 + self._generateNewId(id_group=id_group, id_count=id_count, new_id = 1 + self._generateNewId(id_group=id_group, id_count=id_count,
default=default) default=default, poison=poison)
return range(new_id - id_count, new_id) return range(new_id - id_count, new_id)
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
......
...@@ -48,7 +48,7 @@ class ZODBContinuousIncreasingIdGenerator(IdGenerator): ...@@ -48,7 +48,7 @@ class ZODBContinuousIncreasingIdGenerator(IdGenerator):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
def _generateNewId(self, id_group, id_count=1, default=None): def _generateNewId(self, id_group, id_count=1, default=None, poison=False):
""" """
Return the new_id from the last_id of the zodb Return the new_id from the last_id of the zodb
Use int to store the last_id, use also a persistant mapping for to be Use int to store the last_id, use also a persistant mapping for to be
...@@ -66,25 +66,25 @@ class ZODBContinuousIncreasingIdGenerator(IdGenerator): ...@@ -66,25 +66,25 @@ class ZODBContinuousIncreasingIdGenerator(IdGenerator):
# Retrieve the last id and increment # Retrieve the last id and increment
new_id = last_id_dict.get(id_group, default - 1) + id_count new_id = last_id_dict.get(id_group, default - 1) + id_count
# Store the new_id in the dictionary # Store the new_id in the dictionary
last_id_dict[id_group] = new_id last_id_dict[id_group] = None if poison else new_id
return new_id return new_id
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewId') 'generateNewId')
def generateNewId(self, id_group=None, default=None): def generateNewId(self, id_group=None, default=None, poison=False):
""" """
Generate the next id in the sequence of ids of a particular group Generate the next id in the sequence of ids of a particular group
""" """
return self._generateNewId(id_group=id_group, default=default) return self._generateNewId(id_group=id_group, default=default, poison=poison)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewIdList') 'generateNewIdList')
def generateNewIdList(self, id_group=None, id_count=1, default=None): def generateNewIdList(self, id_group=None, id_count=1, default=None, poison=False):
""" """
Generate a list of next ids in the sequence of ids of a particular group Generate a list of next ids in the sequence of ids of a particular group
""" """
new_id = 1 + self._generateNewId(id_group=id_group, id_count=id_count, new_id = 1 + self._generateNewId(id_group=id_group, id_count=id_count,
default=default) default=default, poison=poison)
return range(new_id - id_count, new_id) return range(new_id - id_count, new_id)
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
......
...@@ -108,7 +108,7 @@ class IdTool(BaseTool): ...@@ -108,7 +108,7 @@ class IdTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewId') 'generateNewId')
def generateNewId(self, id_group=None, default=None, method=_marker, def generateNewId(self, id_group=None, default=None, method=_marker,
id_generator=None): id_generator=None, poison=False):
""" """
Generate the next id in the sequence of ids of a particular group Generate the next id in the sequence of ids of a particular group
""" """
...@@ -127,8 +127,11 @@ class IdTool(BaseTool): ...@@ -127,8 +127,11 @@ class IdTool(BaseTool):
#use _getLatestGeneratorValue here for that the technical level #use _getLatestGeneratorValue here for that the technical level
#must not call the method #must not call the method
last_generator = self._getLatestGeneratorValue(id_generator) last_generator = self._getLatestGeneratorValue(id_generator)
new_id = last_generator.generateNewId(id_group=id_group, \ new_id = last_generator.generateNewId(
default=default) id_group=id_group,
default=default,
poison=poison,
)
except KeyError: except KeyError:
# XXX backward compatiblity # XXX backward compatiblity
if self.getTypeInfo(): if self.getTypeInfo():
...@@ -165,7 +168,7 @@ class IdTool(BaseTool): ...@@ -165,7 +168,7 @@ class IdTool(BaseTool):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'generateNewIdList') 'generateNewIdList')
def generateNewIdList(self, id_group=None, id_count=1, default=None, def generateNewIdList(self, id_group=None, id_count=1, default=None,
store=_marker, id_generator=None): store=_marker, id_generator=None, poison=False):
""" """
Generate a list of next ids in the sequence of ids of a particular group Generate a list of next ids in the sequence of ids of a particular group
""" """
...@@ -186,7 +189,7 @@ class IdTool(BaseTool): ...@@ -186,7 +189,7 @@ class IdTool(BaseTool):
#must not call the method #must not call the method
last_generator = self._getLatestGeneratorValue(id_generator) last_generator = self._getLatestGeneratorValue(id_generator)
new_id_list = last_generator.generateNewIdList(id_group=id_group, new_id_list = last_generator.generateNewIdList(id_group=id_group,
id_count=id_count, default=default) id_count=id_count, default=default, poison=poison)
except (KeyError, ValueError): except (KeyError, ValueError):
# XXX backward compatiblity # XXX backward compatiblity
if self.getTypeInfo(): if self.getTypeInfo():
......
BEGIN BEGIN
<dtml-var sql_delimiter> <dtml-var sql_delimiter>
INSERT INTO portal_ids (`id_group`, `last_id`) INSERT INTO portal_ids (`id_group`, `last_id`)
VALUES (<dtml-sqlvar id_group type="string">, <dtml-sqlvar last_id type="int">) VALUES (<dtml-sqlvar id_group type="string">, <dtml-sqlvar last_id type="int" optional>)
ON DUPLICATE KEY UPDATE `last_id` = <dtml-sqlvar last_id type="int"> ON DUPLICATE KEY UPDATE `last_id` = <dtml-sqlvar last_id type="int" optional>
<dtml-var sql_delimiter> <dtml-var sql_delimiter>
COMMIT COMMIT
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment