Commit 11f57b83 authored by Julien Muchembled's avatar Julien Muchembled

bootstrap: retry migration if previous transaction failed

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@45644 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 5d3fc674
...@@ -59,6 +59,8 @@ import warnings ...@@ -59,6 +59,8 @@ import warnings
from UserDict import IterableUserDict from UserDict import IterableUserDict
from Shared.DC.ZRDB.TM import TM from Shared.DC.ZRDB.TM import TM
from threading import local from threading import local
import transaction.interfaces
import zope.interface
class TransactionalVariable(TM, IterableUserDict): class TransactionalVariable(TM, IterableUserDict):
"""TransactionalVariable provides a dict-like look-n-feel. """TransactionalVariable provides a dict-like look-n-feel.
...@@ -97,3 +99,25 @@ def getTransactionalVariable(context=_MARKER): ...@@ -97,3 +99,25 @@ def getTransactionalVariable(context=_MARKER):
tv = TransactionalVariable() tv = TransactionalVariable()
transactional_variable_pool.instance = tv transactional_variable_pool.instance = tv
return tv return tv
class TransactionalResource(object):
zope.interface.implements(transaction.interfaces.IDataManager)
def __init__(self, transaction_manager=None, **kw):
if transaction_manager is None:
from transaction import manager as transaction_manager
self.__dict__.update(kw, transaction_manager=transaction_manager)
transaction_manager.get().join(self)
@classmethod
def registerOnce(cls, *args):
tv = getTransactionalVariable().setdefault(cls, set())
return not (args in tv or tv.add(args))
def sortKey(self):
return 1
abort = commit = tpc_vote = tpc_begin = tpc_finish = tpc_abort = \
lambda self, transaction: None
...@@ -40,6 +40,7 @@ from Products.ERP5Type.Utils import setDefaultClassProperties ...@@ -40,6 +40,7 @@ from Products.ERP5Type.Utils import setDefaultClassProperties
from Products.ERP5Type import document_class_registry, mixin_class_registry from Products.ERP5Type import document_class_registry, mixin_class_registry
from Products.ERP5Type.dynamic.accessor_holder import AccessorHolderModuleType, \ from Products.ERP5Type.dynamic.accessor_holder import AccessorHolderModuleType, \
createAllAccessorHolderList createAllAccessorHolderList
from Products.ERP5Type.TransactionalVariable import TransactionalResource
from zLOG import LOG, ERROR, INFO, WARNING from zLOG import LOG, ERROR, INFO, WARNING
...@@ -337,7 +338,11 @@ def synchronizeDynamicModules(context, force=False): ...@@ -337,7 +338,11 @@ def synchronizeDynamicModules(context, force=False):
Base.aq_method_lock.acquire() Base.aq_method_lock.acquire()
try: try:
if portal.id not in _bootstrapped: # Thanks to TransactionalResource, the '_bootstrapped' global variable
# is updated in a transactional way. Without it, it would be required to
# restart the instance if anything went wrong.
if portal.id not in _bootstrapped and \
TransactionalResource.registerOnce(__name__, 'bootstrap', portal.id):
migrate = False migrate = False
from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool from Products.ERP5Type.Tool.PropertySheetTool import PropertySheetTool
from Products.ERP5Type.Tool.TypesTool import TypesTool from Products.ERP5Type.Tool.TypesTool import TypesTool
...@@ -366,10 +371,12 @@ def synchronizeDynamicModules(context, force=False): ...@@ -366,10 +371,12 @@ def synchronizeDynamicModules(context, force=False):
if PickleUpdater.get: if PickleUpdater.get:
portal.migrateToPortalTypeClass() portal.migrateToPortalTypeClass()
portal.portal_skins.changeSkin(None) portal.portal_skins.changeSkin(None)
TransactionalResource(tpc_finish=lambda txn:
_bootstrapped.add(portal.id))
LOG('ERP5Site', INFO, 'Transition successful, please update your' LOG('ERP5Site', INFO, 'Transition successful, please update your'
' business templates') ' business templates')
else:
_bootstrapped.add(portal.id) _bootstrapped.add(portal.id)
LOG("ERP5Type.dynamic", 0, "Resetting dynamic classes") LOG("ERP5Type.dynamic", 0, "Resetting dynamic classes")
try: try:
......
...@@ -54,6 +54,11 @@ implements_tuple_list = [ ...@@ -54,6 +54,11 @@ implements_tuple_list = [
class TestERP5TypeInterfaces(ERP5TypeTestCase): class TestERP5TypeInterfaces(ERP5TypeTestCase):
"""Tests implementation of interfaces""" """Tests implementation of interfaces"""
def testTransactionalResource(self):
from Products.ERP5Type.TransactionalVariable import TransactionalResource
from transaction.interfaces import IDataManager
verifyClass(IDataManager, TransactionalResource)
def makeTestMethod(import_tuple, interface): def makeTestMethod(import_tuple, interface):
"""Common method which checks if documents implements interface""" """Common method which checks if documents implements interface"""
def testMethod(self): def testMethod(self):
......
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