Jackrabbit Content Repository
  1. Jackrabbit Content Repository
  2. JCR-2633

Modified externally exception when modifying mixinTypes with single session

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Critical Critical
    • Resolution: Unresolved
    • Affects Version/s: 1.5.7, 2.0, 2.1
    • Fix Version/s: None
    • Component/s: jackrabbit-core
    • Labels:
      None
    • Environment:
      Bundle persistency manager based storage, Jackrabbit 1.5.7 but issue also present in newer versions

      Description

      When first adding mixins and later removing all mixins, a system under heavy stress might experience a modified externally exception even though there is only a single session into the repository.
      The unit test with forced GC and shrinking of caches indicates the problem.

      The unit test itself is mostly trivial, the problem arrises when you add a
      mixin to a node, save it, do this again with another mixin and then remove
      both mixins and in the following save the shared item state cache is shrunk,
      and the garbage collectors hits at exactly the right time. In the unit test a
      reference to the jcr:mixinTypes property must have been held.

      What will happen is that the ItemState of the jcr:mixinTypes property will get
      a modification count higher than 0 when addin the mixins. Because a reference
      to the property is kept, it will not be evicted from the primary cache in the
      local item state manager. When removing all mixins, an overlayed state will
      be created of this ItemState. Because the state and overlayed state are
      linked, the ItemState won't be dropped from the primary cache of the shared
      item state manager.

      But is MAY be evicted from the secondary cache implementing the LRU/FIFO
      functionality. If this is the case when while persisting the changes there is
      a small window where the overlayed state will be disconnected from the state.
      This happens just before collecting the changelog at:
      o.a.j.c.state.ItemState.disconnect():211
      o.a.j.c.state.SessionItemStateManager.disconnectTransientItemState():674
      o.a.j.c.PropertyImpl.makePersistent():143
      o.a.j.c.ItemImpl.persistTransientItems():609
      o.a.j.c.ItemImpl.save():1087
      o.a.j.c.SessionImpl.save():858
      Or in the when actually collecting the changelog in one of the methods
      Changelog.{modified(),deleted() or both. I think the latter, but not really
      sure.

      In any case, this breaks the bondage that prevents the cached state in the
      shared item state manager.

      Now if the shared item state cache has been shrunk enough and the GC hits
      before o.a.j.c.state.SharedItemStateManager.Update.begin():650 when the
      disconnected state will be purged from the shared item state cache. Just
      below line 650 the check for stale items will then cause a re-retrieval from
      the persisted store of the property. Because that state will have a
      modification count of 0, it will conflict with the modification count of the
      mixin property type that is being persisted.

      It is true that the GC needs to go off at exactly the right time and the
      secondary cache needs to have shrunk to be able to evict the item. This can
      however happen in extreme cases. The patch that contains the unit test
      contains code that will force the purging of the item.

      There is still the matter why the modcount comes back at 0 when retrieving the
      property from the persistence manager, basically the assumption made in the
      code between session, local, and shared item state managers, their caches,
      etcetera is that the modification count in the shared item state is always
      incremented, and never reset.

      There is an apparent contract (partially documented) that the modification
      count is to be persisted. Which is in fact the case for the InMemPersistence-
      Manager, but all bundle derived persistence managers do not persist the
      jcr:mixinType property at all, but just the mixintypes as part of the
      nodedefinition information. This means that the jcr:mixinTypes property will
      always be re-created with modcount of 0, which leads to clashes.

      1. persistMixinTypes.patch
        9 kB
        Berry van Halderen
      2. holdrefs.patch
        7 kB
        Berry van Halderen
      3. issue.patch
        18 kB
        Berry van Halderen

        Activity

        Hide
        Berry van Halderen added a comment -

        Unit test including some patch that triggers a GC and shrinking of cache at the right time to trigger the issue.

        Show
        Berry van Halderen added a comment - Unit test including some patch that triggers a GC and shrinking of cache at the right time to trigger the issue.
        Hide
        Berry van Halderen added a comment -

        The holdrefs.patch patches the issue in a relative ugly way, but effective. The secondary changes the storage scheme, but is more in line with the intended implementation IMHO.

        Show
        Berry van Halderen added a comment - The holdrefs.patch patches the issue in a relative ugly way, but effective. The secondary changes the storage scheme, but is more in line with the intended implementation IMHO.
        Hide
        Stefan Guggisberg added a comment -

        +1 in general for the persistMixinTypes.patch

        -1 for making the SISM cache pluggable.

        the 'cache' of the SISM is not a 'cache' in the traditional sense
        but has special semantics which are essential in maintaining data
        integrity and are an integral part of jackrabbit's implementation of
        isolation levels (read committed). making it 'pluggable' would
        probably open the door for lots of new issues where people used
        some supposedly 'better' generic caching framework and are
        surprised when they encounter corrupted repositories...

        Show
        Stefan Guggisberg added a comment - +1 in general for the persistMixinTypes.patch -1 for making the SISM cache pluggable. the 'cache' of the SISM is not a 'cache' in the traditional sense but has special semantics which are essential in maintaining data integrity and are an integral part of jackrabbit's implementation of isolation levels (read committed). making it 'pluggable' would probably open the door for lots of new issues where people used some supposedly 'better' generic caching framework and are surprised when they encounter corrupted repositories...
        Hide
        Marcel Reutegger added a comment -

        How is backward compatibility handled with persistMixinTypes.patch?

        Show
        Marcel Reutegger added a comment - How is backward compatibility handled with persistMixinTypes.patch?

          People

          • Assignee:
            Unassigned
            Reporter:
            Berry van Halderen
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development