Make sure to save in atomic transaction. Resovle #2657.
This commit is contained in:
parent
b4042641b1
commit
4f8753b683
3 changed files with 35 additions and 12 deletions
|
|
@ -7,9 +7,12 @@ Unit test module for Trait classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
from anything import Something
|
from anything import Something
|
||||||
|
from evennia.objects.objects import DefaultCharacter
|
||||||
|
from evennia.utils.test_resources import BaseEvenniaTestCase, EvenniaTest
|
||||||
from mock import MagicMock, patch
|
from mock import MagicMock, patch
|
||||||
from evennia.utils.test_resources import BaseEvenniaTestCase
|
|
||||||
from . import traits
|
from . import traits
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1040,3 +1043,22 @@ class TestTraitFields(BaseEvenniaTestCase):
|
||||||
|
|
||||||
self.assertEqual(13, obj2.strength.value)
|
self.assertEqual(13, obj2.strength.value)
|
||||||
self.assertEqual(20, obj.strength.value)
|
self.assertEqual(20, obj.strength.value)
|
||||||
|
|
||||||
|
|
||||||
|
class TraitContribTestingChar(DefaultCharacter):
|
||||||
|
HP = traits.TraitProperty("health", trait_type="trait", value=5)
|
||||||
|
|
||||||
|
|
||||||
|
class TraitPropertyTestCase(EvenniaTest):
|
||||||
|
"""
|
||||||
|
Test atomic updating.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
character_typeclass = TraitContribTestingChar
|
||||||
|
|
||||||
|
def test_round1(self):
|
||||||
|
self.char1.HP.value = 1
|
||||||
|
|
||||||
|
def test_round2(self):
|
||||||
|
self.char1.HP.value = 2
|
||||||
|
|
|
||||||
|
|
@ -1629,8 +1629,6 @@ class EvTable(object):
|
||||||
htable = self.nrows
|
htable = self.nrows
|
||||||
excess = len(row) - wtable
|
excess = len(row) - wtable
|
||||||
|
|
||||||
print(" len(row):", len(row), "wtable:", wtable, "excess:", excess)
|
|
||||||
|
|
||||||
if excess > 0:
|
if excess > 0:
|
||||||
# we need to add new empty columns to table
|
# we need to add new empty columns to table
|
||||||
empty_rows = ["" for _ in range(htable)]
|
empty_rows = ["" for _ in range(htable)]
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,20 @@ leave caching unexpectedly (no use of WeakRefs).
|
||||||
Also adds `cache_size()` for monitoring the size of the cache.
|
Also adds `cache_size()` for monitoring the size of the cache.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import gc
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import gc
|
|
||||||
import time
|
import time
|
||||||
from weakref import WeakValueDictionary
|
from weakref import WeakValueDictionary
|
||||||
from twisted.internet.reactor import callFromThread
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist, FieldError
|
from django.core.exceptions import FieldError, ObjectDoesNotExist
|
||||||
from django.db.models.signals import post_save
|
|
||||||
from django.db.models.base import Model, ModelBase
|
from django.db.models.base import Model, ModelBase
|
||||||
from django.db.models.signals import pre_delete, post_migrate
|
from django.db.models.signals import post_migrate, post_save, pre_delete
|
||||||
|
from django.db.transaction import atomic
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils.utils import dbref, get_evennia_pids, to_str
|
from evennia.utils.utils import dbref, get_evennia_pids, to_str
|
||||||
|
from twisted.internet.reactor import callFromThread
|
||||||
|
|
||||||
from .manager import SharedMemoryManager
|
from .manager import SharedMemoryManager
|
||||||
|
|
||||||
|
|
@ -444,12 +445,14 @@ class SharedMemoryModel(Model, metaclass=SharedMemoryModelBase):
|
||||||
if _IS_MAIN_THREAD:
|
if _IS_MAIN_THREAD:
|
||||||
# in main thread - normal operation
|
# in main thread - normal operation
|
||||||
try:
|
try:
|
||||||
|
with atomic():
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
except DatabaseError:
|
except DatabaseError:
|
||||||
# we handle the 'update_fields did not update any rows' error that
|
# we handle the 'update_fields did not update any rows' error that
|
||||||
# may happen due to timing issues with attributes
|
# may happen due to timing issues with attributes
|
||||||
ufields_removed = kwargs.pop("update_fields", None)
|
ufields_removed = kwargs.pop("update_fields", None)
|
||||||
if ufields_removed:
|
if ufields_removed:
|
||||||
|
with atomic():
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
@ -623,8 +626,8 @@ def conditional_flush(max_rmem, force=False):
|
||||||
if ((now - LAST_FLUSH) < AUTO_FLUSH_MIN_INTERVAL) and not force:
|
if ((now - LAST_FLUSH) < AUTO_FLUSH_MIN_INTERVAL) and not force:
|
||||||
# too soon after last flush.
|
# too soon after last flush.
|
||||||
logger.log_warn(
|
logger.log_warn(
|
||||||
"Warning: Idmapper flush called more than "
|
"Warning: Idmapper flush called more than once in %s min interval. Check memory usage."
|
||||||
"once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL / 60.0)
|
% (AUTO_FLUSH_MIN_INTERVAL / 60.0)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue