private void tileEncoderSink(Iterable<TileBatch> prev) throws IOException {
    /*
     * To optimize emitting many identical consecutive tiles (like large ocean areas), memoize output to avoid
     * recomputing if the input hasn't changed.
     */
    byte[] lastBytes = null, lastEncoded = null;
    Long lastTileDataHash = null;
    boolean lastIsFill = false;
    List<TileSizeStats.LayerStats> lastLayerStats = null;
    boolean skipFilled = config.skipFilledTiles();
    var layerStatsSerializer = TileSizeStats.newThreadLocalSerializer();

    var tileStatsUpdater = tileStats.threadLocalUpdater();
    var layerAttrStatsUpdater = layerAttrStats.handlerForThread();
    for (TileBatch batch : prev) {
      List<TileEncodingResult> result = new ArrayList<>(batch.size());
      FeatureGroup.TileFeatures last = null;
      // each batch contains tile ordered by tile-order ID ascending
      for (int i = 0; i < batch.in.size(); i++) {
        FeatureGroup.TileFeatures tileFeatures = batch.in.get(i);
        featuresProcessed.incBy(tileFeatures.getNumFeaturesProcessed());
        byte[] bytes, encoded;
        List<TileSizeStats.LayerStats> layerStats;
        Long tileDataHash;
        if (tileFeatures.hasSameContents(last)) {
          bytes = lastBytes;
          encoded = lastEncoded;
          tileDataHash = lastTileDataHash;
          layerStats = lastLayerStats;
          memoizedTiles.inc();
        } else {
          VectorTile tile = tileFeatures.getVectorTile(layerAttrStatsUpdater);
          if (skipFilled && (lastIsFill = tile.containsOnlyFills())) {
            encoded = null;
            layerStats = null;
            bytes = null;
          } else {
            var proto = tile.toProto();
            encoded = proto.toByteArray();
            bytes = switch (config.tileCompression()) {
              case GZIP -> gzip(encoded);
              case NONE -> encoded;
              case UNKNOWN -> throw new IllegalArgumentException("cannot compress \"UNKNOWN\"");
            };
            layerStats = TileSizeStats.computeTileStats(proto);
            if (encoded.length > config.tileWarningSizeBytes()) {
              LOGGER.warn("{} {}kb uncompressed",
                tileFeatures.tileCoord(),
                encoded.length / 1024);
            }
          }
          lastLayerStats = layerStats;
          lastEncoded = encoded;
          lastBytes = bytes;
          last = tileFeatures;
          if (archive.deduplicates() && tile.likelyToBeDuplicated() && bytes != null) {
            tileDataHash = generateContentHash(bytes);
          } else {
            tileDataHash = null;
          }
          lastTileDataHash = tileDataHash;
        }
        if ((!skipFilled || !lastIsFill) && bytes != null) {
          tileStatsUpdater.recordTile(tileFeatures.tileCoord(), bytes.length, layerStats);
          List<String> layerStatsRows = config.outputLayerStats() ?
            layerStatsSerializer.formatOutputRows(tileFeatures.tileCoord(), bytes.length, layerStats) :
            List.of();
          result.add(
            new TileEncodingResult(
              tileFeatures.tileCoord(),
              bytes,
              encoded.length,
              tileDataHash == null ? OptionalLong.empty() : OptionalLong.of(tileDataHash),
              layerStatsRows
            )
          );
        }
      }
      // hand result off to writer
      batch.out.complete(result);
    }
  }
Reads all {@code features}, encodes them in parallel, and writes to {@code output}.
planetiler-core/src/main/java/com/onthegomap/planetiler/archive/TileArchiveWriter.java