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 anything import Something
from evennia.objects.objects import DefaultCharacter
from evennia.utils.test_resources import BaseEvenniaTestCase, EvenniaTest
from mock import MagicMock, patch
from evennia.utils.test_resources import BaseEvenniaTestCase
from . import traits
@ -1040,3 +1043,22 @@ class TestTraitFields(BaseEvenniaTestCase):
self.assertEqual(13, obj2.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
excess = len(row) - wtable
print(" len(row):", len(row), "wtable:", wtable, "excess:", excess)
if excess > 0:
# we need to add new empty columns to table
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.
"""
import gc
import os
import threading
import gc
import time
from weakref import WeakValueDictionary
from twisted.internet.reactor import callFromThread
from django.core.exceptions import ObjectDoesNotExist, FieldError
from django.db.models.signals import post_save
from django.core.exceptions import FieldError, ObjectDoesNotExist
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 evennia.utils import logger
from evennia.utils.utils import dbref, get_evennia_pids, to_str
from twisted.internet.reactor import callFromThread
from .manager import SharedMemoryManager
@ -444,13 +445,15 @@ class SharedMemoryModel(Model, metaclass=SharedMemoryModelBase):
if _IS_MAIN_THREAD:
# in main thread - normal operation
try:
super().save(*args, **kwargs)
with atomic():
super().save(*args, **kwargs)
except DatabaseError:
# we handle the 'update_fields did not update any rows' error that
# may happen due to timing issues with attributes
ufields_removed = kwargs.pop("update_fields", None)
if ufields_removed:
super().save(*args, **kwargs)
with atomic():
super().save(*args, **kwargs)
else:
raise
else:
@ -623,8 +626,8 @@ def conditional_flush(max_rmem, force=False):
if ((now - LAST_FLUSH) < AUTO_FLUSH_MIN_INTERVAL) and not force:
# too soon after last flush.
logger.log_warn(
"Warning: Idmapper flush called more than "
"once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL / 60.0)
"Warning: Idmapper flush called more than once in %s min interval. Check memory usage."
% (AUTO_FLUSH_MIN_INTERVAL / 60.0)
)
return