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

io.atomix.raft.storage.serializer.RaftEntrySBESerializer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2020 camunda services GmbH ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.atomix.raft.storage.serializer;

import static io.atomix.raft.storage.serializer.SerializerUtil.getRaftMemberType;
import static io.atomix.raft.storage.serializer.SerializerUtil.getSBEType;

import io.atomix.cluster.MemberId;
import io.atomix.raft.cluster.RaftMember;
import io.atomix.raft.cluster.impl.DefaultRaftMember;
import io.atomix.raft.storage.log.entry.ApplicationEntry;
import io.atomix.raft.storage.log.entry.ConfigurationEntry;
import io.atomix.raft.storage.log.entry.InitialEntry;
import io.atomix.raft.storage.log.entry.RaftLogEntry;
import io.atomix.raft.storage.log.entry.SerializedApplicationEntry;
import io.atomix.raft.storage.serializer.ConfigurationEntryDecoder.NewMembersDecoder;
import io.atomix.raft.storage.serializer.ConfigurationEntryDecoder.OldMembersDecoder;
import io.camunda.zeebe.journal.file.RecordDataEncoder;
import io.camunda.zeebe.util.SbeUtil;
import java.nio.ByteOrder;
import java.time.Instant;
import java.util.ArrayList;
import org.agrona.DirectBuffer;
import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.UnsafeBuffer;

public class RaftEntrySBESerializer implements RaftEntrySerializer {
  final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder();
  final RaftLogEntryEncoder raftLogEntryEncoder = new RaftLogEntryEncoder();
  final ApplicationEntryEncoder applicationEntryEncoder = new ApplicationEntryEncoder();
  final ConfigurationEntryEncoder configurationEntryEncoder = new ConfigurationEntryEncoder();
  final MessageHeaderDecoder headerDecoder = new MessageHeaderDecoder();
  final RaftLogEntryDecoder raftLogEntryDecoder = new RaftLogEntryDecoder();
  final ApplicationEntryDecoder applicationEntryDecoder = new ApplicationEntryDecoder();
  final ConfigurationEntryDecoder configurationEntryDecoder = new ConfigurationEntryDecoder();

  @Override
  public int getApplicationEntrySerializedLength(final ApplicationEntry entry) {
    // raft frame length
    return headerEncoder.encodedLength()
        + raftLogEntryEncoder.sbeBlockLength()
        // + application entry length
        + headerEncoder.encodedLength()
        + applicationEntryEncoder.sbeBlockLength()
        + RecordDataEncoder.dataHeaderLength()
        + entry.dataWriter().getLength();
  }

  @Override
  public int getInitialEntrySerializedLength() {
    return headerEncoder.encodedLength() + raftLogEntryEncoder.sbeBlockLength();
  }

  @Override
  public int getConfigurationEntrySerializedLength(final ConfigurationEntry entry) {
    // raft frame length
    return headerEncoder.encodedLength()
        + raftLogEntryEncoder.sbeBlockLength()
        // configuration entry length
        + headerEncoder.encodedLength()
        // timestamp
        + configurationEntryEncoder.sbeBlockLength()
        // new members header
        + NewMembersDecoder.sbeHeaderSize()
        // new member entries
        + entry.newMembers().stream().mapToInt(this::getNewMemberEntryLength).sum()
        // old members header
        + OldMembersDecoder.sbeHeaderSize()
        // old member entries
        + entry.oldMembers().stream().mapToInt(this::getOldMemberEntryLength).sum();
  }

  @Override
  public int writeApplicationEntry(
      final long term,
      final ApplicationEntry entry,
      final MutableDirectBuffer buffer,
      final int offset) {

    final int entryOffset = writeRaftFrame(term, EntryType.ApplicationEntry, buffer, offset);

    headerEncoder
        .wrap(buffer, offset + entryOffset)
        .blockLength(applicationEntryEncoder.sbeBlockLength())
        .templateId(applicationEntryEncoder.sbeTemplateId())
        .schemaId(applicationEntryEncoder.sbeSchemaId())
        .version(applicationEntryEncoder.sbeSchemaVersion());
    applicationEntryEncoder.wrap(buffer, offset + entryOffset + headerEncoder.encodedLength());
    applicationEntryEncoder.lowestAsqn(entry.lowestPosition()).highestAsqn(entry.highestPosition());
    SbeUtil.writeNested(
        entry.dataWriter(),
        ApplicationEntryEncoder.applicationDataHeaderLength(),
        applicationEntryEncoder,
        ByteOrder.LITTLE_ENDIAN);

    return entryOffset + headerEncoder.encodedLength() + applicationEntryEncoder.encodedLength();
  }

  @Override
  public int writeInitialEntry(
      final long term,
      final InitialEntry entry,
      final MutableDirectBuffer buffer,
      final int offset) {

    return writeRaftFrame(term, EntryType.InitialEntry, buffer, offset);
  }

  @Override
  public int writeConfigurationEntry(
      final long term,
      final ConfigurationEntry entry,
      final MutableDirectBuffer buffer,
      final int offset) {
    final int entryOffset = writeRaftFrame(term, EntryType.ConfigurationEntry, buffer, offset);

    headerEncoder
        .wrap(buffer, offset + entryOffset)
        .blockLength(configurationEntryEncoder.sbeBlockLength())
        .templateId(configurationEntryEncoder.sbeTemplateId())
        .schemaId(configurationEntryEncoder.sbeSchemaId())
        .version(configurationEntryEncoder.sbeSchemaVersion());

    configurationEntryEncoder.wrap(buffer, offset + entryOffset + headerEncoder.encodedLength());

    configurationEntryEncoder.timestamp(entry.timestamp());

    final var newMembersEncoder =
        configurationEntryEncoder.newMembersCount(entry.newMembers().size());
    for (final RaftMember member : entry.newMembers()) {
      final var memberId = member.memberId().id();
      newMembersEncoder
          .next()
          .type(getSBEType(member.getType()))
          .updated(member.getLastUpdated().toEpochMilli())
          .memberId(memberId);
    }

    final var oldMembersEncoder =
        configurationEntryEncoder.oldMembersCount(entry.oldMembers().size());
    for (final RaftMember member : entry.oldMembers()) {
      final var memberId = member.memberId().id();
      oldMembersEncoder
          .next()
          .type(getSBEType(member.getType()))
          .updated(member.getLastUpdated().toEpochMilli())
          .memberId(memberId);
    }

    return entryOffset + headerEncoder.encodedLength() + configurationEntryEncoder.encodedLength();
  }

  @Override
  public RaftLogEntry readRaftLogEntry(final DirectBuffer buffer) {
    headerDecoder.wrap(buffer, 0);
    raftLogEntryDecoder.wrap(
        buffer,
        headerDecoder.encodedLength(),
        headerDecoder.blockLength(),
        headerDecoder.version());
    final long term = raftLogEntryDecoder.term();
    final EntryType type = raftLogEntryDecoder.type();

    final int entryOffset = headerDecoder.encodedLength() + raftLogEntryDecoder.encodedLength();

    final var entry =
        switch (type) {
          case ApplicationEntry -> {
            headerDecoder.wrap(buffer, entryOffset);
            yield readApplicationEntry(buffer, entryOffset);
          }
          case ConfigurationEntry -> {
            headerDecoder.wrap(buffer, entryOffset);
            yield readConfigurationEntry(buffer, entryOffset);
          }
          case InitialEntry -> new InitialEntry();
          default -> throw new IllegalStateException("Unexpected entry type " + type);
        };

    return new RaftLogEntry(term, entry);
  }

  private int getNewMemberEntryLength(final RaftMember raftMember) {
    final String id = raftMember.memberId().id();
    return NewMembersDecoder.sbeBlockLength()
        + NewMembersDecoder.memberIdHeaderLength()
        + ((null == id || id.isEmpty()) ? 0 : id.length());
  }

  private int getOldMemberEntryLength(final RaftMember raftMember) {
    final String id = raftMember.memberId().id();
    return OldMembersDecoder.sbeBlockLength()
        + OldMembersDecoder.memberIdHeaderLength()
        + ((null == id || id.isEmpty()) ? 0 : id.length());
  }

  private int writeRaftFrame(
      final long term,
      final EntryType entryType,
      final MutableDirectBuffer buffer,
      final int offset) {
    headerEncoder
        .wrap(buffer, offset)
        .blockLength(raftLogEntryEncoder.sbeBlockLength())
        .templateId(raftLogEntryEncoder.sbeTemplateId())
        .schemaId(raftLogEntryEncoder.sbeSchemaId())
        .version(raftLogEntryEncoder.sbeSchemaVersion());
    raftLogEntryEncoder.wrap(buffer, offset + headerEncoder.encodedLength());
    raftLogEntryEncoder.term(term);
    raftLogEntryEncoder.type(entryType);

    return headerEncoder.encodedLength() + raftLogEntryEncoder.encodedLength();
  }

  private ApplicationEntry readApplicationEntry(final DirectBuffer buffer, final int entryOffset) {
    applicationEntryDecoder.wrap(
        buffer,
        entryOffset + headerDecoder.encodedLength(),
        headerDecoder.blockLength(),
        headerDecoder.version());

    final DirectBuffer data = new UnsafeBuffer();
    applicationEntryDecoder.wrapApplicationData(data);

    return new SerializedApplicationEntry(
        applicationEntryDecoder.lowestAsqn(), applicationEntryDecoder.highestAsqn(), data);
  }

  private ConfigurationEntry readConfigurationEntry(
      final DirectBuffer buffer, final int entryOffset) {

    configurationEntryDecoder.wrap(
        buffer,
        entryOffset + headerDecoder.encodedLength(),
        headerDecoder.blockLength(),
        headerDecoder.version());

    final long timestamp = configurationEntryDecoder.timestamp();

    final NewMembersDecoder newMembersDecoder = configurationEntryDecoder.newMembers();
    final ArrayList newMembers = new ArrayList<>(newMembersDecoder.count());
    for (final NewMembersDecoder member : newMembersDecoder) {
      final RaftMember.Type type = getRaftMemberType(member.type());
      final Instant updated = Instant.ofEpochMilli(member.updated());
      final var memberId = member.memberId();
      newMembers.add(new DefaultRaftMember(MemberId.from(memberId), type, updated));
    }

    final OldMembersDecoder oldMembersDecoder = configurationEntryDecoder.oldMembers();
    final ArrayList oldMembers = new ArrayList<>(oldMembersDecoder.count());
    for (final OldMembersDecoder member : oldMembersDecoder) {
      final RaftMember.Type type = getRaftMemberType(member.type());
      final Instant updated = Instant.ofEpochMilli(member.updated());
      final var memberId = member.memberId();
      oldMembers.add(new DefaultRaftMember(MemberId.from(memberId), type, updated));
    }

    return new ConfigurationEntry(timestamp, newMembers, oldMembers);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy