Make sure to save in atomic transaction. Resovle #2657.

This commit is contained in:
Griatch 2022-09-25 00:36:37 +02:00
parent b4042641b1
commit 4f8753b683
3 changed files with 35 additions and 12 deletions

View file

@ -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

View file

@ -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)]

View file

@ -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