@Override
    protected void commitSingleEntry(
        CacheEntry entry,
        Metadata metadata,
        FlagAffectedCommand command,
        InvocationContext ctx,
        Flag trackFlag,
        boolean l1Invalidation) {
      // Cache flags before they're reset
      // TODO: Can the reset be done after notification instead?
      boolean created = entry.isCreated();
      boolean removed = entry.isRemoved();
      boolean expired;
      if (removed && entry instanceof MVCCEntry) {
        expired = ((MVCCEntry) entry).isExpired();
      } else {
        expired = false;
      }

      InternalCacheEntry previousEntry = dataContainer.peek(entry.getKey());
      Object previousValue = null;
      Metadata previousMetadata = null;
      if (previousEntry != null) {
        previousValue = previousEntry.getValue();
        previousMetadata = previousEntry.getMetadata();
      }
      commitManager.commit(entry, metadata, trackFlag, l1Invalidation);

      // Notify after events if necessary
      notifyCommitEntry(
          created, removed, expired, entry, ctx, command, previousValue, previousMetadata);
    }
    @Override
    protected void commitSingleEntry(
        CacheEntry entry,
        Metadata metadata,
        FlagAffectedCommand command,
        InvocationContext ctx,
        Flag trackFlag,
        boolean l1Invalidation) {
      // Don't allow the CH to change (and state transfer to invalidate entries)
      // between the ownership check and the commit
      stateTransferLock.acquireSharedTopologyLock();
      try {
        boolean doCommit = true;
        // ignore locality for removals, even if skipOwnershipCheck is not true
        boolean skipOwnershipCheck = command != null && command.hasFlag(Flag.SKIP_OWNERSHIP_CHECK);

        boolean isForeignOwned = !skipOwnershipCheck && !localNodeIsOwner(entry.getKey());
        if (isForeignOwned && !entry.isRemoved()) {
          if (configuration.clustering().l1().enabled()) {
            // transform for L1
            long lifespan;
            if (metadata != null) {
              lifespan = metadata.lifespan();
            } else {
              lifespan = entry.getLifespan();
            }
            if (lifespan < 0 || lifespan > configuration.clustering().l1().lifespan()) {
              Metadata.Builder builder;
              if (metadata != null) {
                builder = metadata.builder();
              } else {
                builder = entry.getMetadata().builder();
              }
              metadata = builder.lifespan(configuration.clustering().l1().lifespan()).build();
            }
          } else {
            doCommit = false;
          }
        }

        boolean created = false;
        boolean removed = false;
        boolean expired = false;
        if (!isForeignOwned) {
          created = entry.isCreated();
          removed = entry.isRemoved();
          if (removed && entry instanceof MVCCEntry) {
            expired = ((MVCCEntry) entry).isExpired();
          }
        }

        if (doCommit) {
          InternalCacheEntry previousEntry = dataContainer.peek(entry.getKey());
          Object previousValue = null;
          Metadata previousMetadata = null;
          if (previousEntry != null) {
            previousValue = previousEntry.getValue();
            previousMetadata = previousEntry.getMetadata();
          }
          commitManager.commit(entry, metadata, trackFlag, l1Invalidation);
          if (!isForeignOwned) {
            notifyCommitEntry(
                created, removed, expired, entry, ctx, command, previousValue, previousMetadata);
          }
        } else entry.rollback();

      } finally {
        stateTransferLock.releaseSharedTopologyLock();
      }
    }