// This invokes the tranformation block if one is installed and queues the resulting CBL_Revision
  private void queueDownloadedRevision(RevisionInternal rev) {

    if (revisionBodyTransformationBlock != null) {
      // Add 'file' properties to attachments pointing to their bodies:

      for (Map.Entry<String, Map<String, Object>> entry :
          ((Map<String, Map<String, Object>>) rev.getProperties().get("_attachments")).entrySet()) {
        String name = entry.getKey();
        Map<String, Object> attachment = entry.getValue();
        attachment.remove("file");
        if (attachment.get("follows") != null && attachment.get("data") == null) {
          String filePath = db.fileForAttachmentDict(attachment).getPath();
          if (filePath != null) attachment.put("file", filePath);
        }
      }

      RevisionInternal xformed = transformRevision(rev);
      if (xformed == null) {
        Log.v(Log.TAG_SYNC, "%s: Transformer rejected revision %s", this, rev);
        pendingSequences.removeSequence(rev.getSequence());
        lastSequence = pendingSequences.getCheckpointedValue();
        pauseOrResume();
        return;
      }
      rev = xformed;

      // Clean up afterwards
      Map<String, Object> attachments =
          (Map<String, Object>) rev.getProperties().get("_attachments");

      for (Map.Entry<String, Map<String, Object>> entry :
          ((Map<String, Map<String, Object>>) rev.getProperties().get("_attachments")).entrySet()) {
        Map<String, Object> attachment = entry.getValue();
        attachment.remove("file");
      }
    }

    if (rev != null && rev.getBody() != null) rev.getBody().compact();

    downloadsToInsert.queueObject(rev);
  }
 /**
  * Removes a revision from the "pending" set after it's been uploaded. Advances checkpoint. -
  * (void) removePending: (CBL_Revision*)rev in CBLRestPusher.m
  */
 @InterfaceAudience.Private
 private void removePending(RevisionInternal revisionInternal) {
   long seq = revisionInternal.getSequence();
   if (pendingSequences == null || pendingSequences.isEmpty()) {
     Log.w(
         Log.TAG_SYNC,
         "%s: removePending() called w/ rev: %s, but pendingSequences empty",
         this,
         revisionInternal);
     if (revisionInternal.getBody() != null) revisionInternal.getBody().release();
     pauseOrResume();
     return;
   }
   boolean wasFirst = (seq == pendingSequences.first());
   if (!pendingSequences.contains(seq)) {
     Log.w(
         Log.TAG_SYNC,
         "%s: removePending: sequence %s not in set, for rev %s",
         this,
         seq,
         revisionInternal);
   }
   pendingSequences.remove(seq);
   if (wasFirst) {
     // If I removed the first pending sequence, can advance the checkpoint:
     long maxCompleted;
     if (pendingSequences.size() == 0) {
       maxCompleted = maxPendingSequence;
     } else {
       maxCompleted = pendingSequences.first();
       --maxCompleted;
     }
     setLastSequence(Long.toString(maxCompleted));
   }
   if (revisionInternal.getBody() != null) revisionInternal.getBody().release();
   pauseOrResume();
 }