docs: void save( AbstractJcrNode node ) throws RepositoryException {
          // first check the node is valid from a cache perspective
          Set<NodeKey> keysToBeSaved = null;
          try {
              if (node.isNew()) {
                  // expected by TCK
                  throw new RepositoryException(JcrI18n.unableToSaveNodeThatWasCreatedSincePreviousSave.text(node.getPath(),
                                                                                                             workspaceName()));
              }
  
              AtomicReference<Set<NodeKey>> refToKeys = new AtomicReference<Set<NodeKey>>();
              if (node.containsChangesWithExternalDependencies(refToKeys)) {
                  // expected by TCK
                  I18n msg = JcrI18n.unableToSaveBranchBecauseChangesDependOnChangesToNodesOutsideOfBranch;
                  throw new ConstraintViolationException(msg.text(node.path(), workspaceName()));
              }
              keysToBeSaved = refToKeys.get();
          } catch (ItemNotFoundException e) {
              throw new InvalidItemStateException(e);
          } catch (NodeNotFoundException e) {
              throw new InvalidItemStateException(e);
          }
          assert keysToBeSaved != null;
  
          SessionCache sessionCache = cache();
          if (sessionCache.getChangedNodeKeys().size() == keysToBeSaved.size()) {
              // The node is above all the other changes, so go ahead and save the whole session ...
              save();
              return;
          }
  
          // Perform the save, using 'JcrPreSave' operations ...
          SessionCache systemCache = createSystemCache(false);
          SystemContent systemContent = new SystemContent(systemCache);
          Map<NodeKey, NodeKey> baseVersionKeys = this.baseVersionKeys.get();
          Map<NodeKey, NodeKey> originalVersionKeys = this.originalVersionKeys.get();
          try {
              sessionCache.save(keysToBeSaved, systemContent.cache(), new JcrPreSave(systemContent, baseVersionKeys,
                                                                                     originalVersionKeys, aclChangesCount()));
          } catch (WrappedException e) {
              Throwable cause = e.getCause();
              throw (cause instanceof RepositoryException) ? (RepositoryException)cause : new RepositoryException(e.getCause());
          } catch (DocumentNotFoundException e) {
              throw new InvalidItemStateException(JcrI18n.nodeModifiedBySessionWasRemovedByAnotherSession.text(e.getKey()), e);
          } catch (DocumentAlreadyExistsException e) {
              // Try to figure out which node in this transient state was the problem ...
              NodeKey key = new NodeKey(e.getKey());
              AbstractJcrNode problemNode = node(key, null);
              String path = problemNode.getPath();
              throw new InvalidItemStateException(JcrI18n.nodeCreatedBySessionUsedExistingKey.text(path, key), e);
          } catch (org.modeshape.jcr.cache.ReferentialIntegrityException e) {
              throw new ReferentialIntegrityException(e);
          } catch (Throwable t) {
              throw new RepositoryException(t);
          }
  
          try {
              // Record the save operation ...
              repository().statistics().increment(ValueMetric.SESSION_SAVES);
          } catch (IllegalStateException e) {
              // The repository has been shutdown ...
          }
      }