All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.camunda.zeebe.logstreams.impl.serializer.LogAppendEntrySerializer Maven / Gradle / Ivy

/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Zeebe Community License 1.1. You may not use this file
 * except in compliance with the Zeebe Community License 1.1.
 */
package io.camunda.zeebe.logstreams.impl.serializer;

import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.metadataOffset;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setKey;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setMetadataLength;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setPosition;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setSourceEventPosition;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setTimestamp;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.setVersion;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.skipProcessing;
import static io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor.valueOffset;

import io.camunda.zeebe.logstreams.impl.log.LogEntryDescriptor;
import io.camunda.zeebe.logstreams.log.LogAppendEntry;
import java.util.Objects;
import org.agrona.MutableDirectBuffer;

/** Serializes {@link LogAppendEntry}, including legacy dispatcher framing. */
final class LogAppendEntrySerializer {
  /**
   * Serializes an entry into the given destination buffer. Returns the length of the serialized
   * entry, framed but unaligned.
   *
   * @param writeBuffer the buffer to serialize into
   * @param writeBufferOffset the offset to start serializing at in the {@code writeBuffer}
   * @param entry the entry to serialize
   * @param position the position of the entry
   * @param sourcePosition the source record position of the entry
   * @param entryTimestamp the timestamp; useful to pass the same for a complete batch, for example
   * @return the length of the serialized entry, with dispatcher framing but not aligned
   * @throws IllegalArgumentException if the entry's value is empty, i.e. has a length of 0
   */
  static int serialize(
      final MutableDirectBuffer writeBuffer,
      final int writeBufferOffset,
      final LogAppendEntry entry,
      final long position,
      final long sourcePosition,
      final long entryTimestamp) {
    Objects.requireNonNull(writeBuffer, "must specify a destination buffer");
    Objects.requireNonNull(entry, "must specify an entry");

    final var key = entry.key();
    final var metadata = entry.recordMetadata();
    final var value = entry.recordValue();
    Objects.requireNonNull(metadata, "must specify metadata");
    Objects.requireNonNull(value, "must specify value");

    if (writeBufferOffset < 0) {
      throw new IllegalArgumentException(
          "Expected to serialize entry at a positive offset, but the offset given was %d"
              .formatted(writeBufferOffset));
    }

    if (value.getLength() == 0) {
      throw new IllegalArgumentException(
          "Expected to serialize an entry with a value, but the entry's value reports a length of 0");
    }

    if (metadata.getLength() == 0) {
      throw new IllegalArgumentException(
          "Expected to serialize an entry with metadata, but the entry's metadata reports a length of 0");
    }

    if (position < 0) {
      throw new IllegalArgumentException(
          "Expected to serialize an entry with a positive position, but the position given was %d"
              .formatted(position));
    }

    if (entryTimestamp < 0) {
      throw new IllegalArgumentException(
          "Expected to serialize an entry with a positive timestamp, but the timestamp given was %d"
              .formatted(entryTimestamp));
    }

    final var metadataLength = metadata.getLength();
    final var framedEntryLength = framedLength(entry);

    // Write the dispatcher framing
    DataFrameDescriptor.setFramedLength(writeBuffer, writeBufferOffset, framedEntryLength);
    final var entryOffset = writeBufferOffset + DataFrameDescriptor.HEADER_LENGTH;

    // Write the entry
    setVersion(writeBuffer, entryOffset);
    if (entry.isProcessed()) {
      skipProcessing(writeBuffer, entryOffset);
    }
    setPosition(writeBuffer, entryOffset, position);
    setSourceEventPosition(writeBuffer, entryOffset, sourcePosition);
    setKey(writeBuffer, entryOffset, key);
    setTimestamp(writeBuffer, entryOffset, entryTimestamp);
    setMetadataLength(writeBuffer, entryOffset, metadataLength);
    metadata.write(writeBuffer, metadataOffset(entryOffset));
    value.write(writeBuffer, valueOffset(entryOffset, metadataLength));

    return framedEntryLength;
  }

  static int framedLength(final LogAppendEntry entry) {
    return DataFrameDescriptor.framedLength(
        LogEntryDescriptor.headerLength(entry.recordMetadata().getLength())
            + entry.recordValue().getLength());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy