Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2019 Pantheon Technologies, s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.controller.akka.segjournal;
import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.japi.pf.ReceiveBuilder;
import akka.persistence.AtomicWrite;
import akka.persistence.PersistentRepr;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.base.MoreObjects;
import com.google.common.base.Stopwatch;
import io.atomix.storage.journal.Indexed;
import io.atomix.storage.journal.JournalSerdes;
import io.atomix.storage.journal.SegmentedByteBufJournal;
import io.atomix.storage.journal.SegmentedJournal;
import io.atomix.storage.journal.StorageLevel;
import java.io.File;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.opendaylight.controller.cluster.common.actor.MeteringBehavior;
import org.opendaylight.controller.cluster.reporting.MetricsReporter;
import org.opendaylight.controller.raft.journal.FromByteBufMapper;
import org.opendaylight.controller.raft.journal.ToByteBufMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.concurrent.Future;
import scala.concurrent.Promise;
/**
* This actor handles a single PersistentActor's journal. The journal is split into two {@link SegmentedJournal}s:
*
*
A memory-mapped data journal, containing actual data entries
*
A simple file journal, containing sequence numbers of last deleted entry
*
*
*
* This is a conscious design decision to minimize the amount of data that is being stored in the data journal while
* speeding up normal operations. Since the SegmentedJournal is an append-only linear log and Akka requires the ability
* to delete persistence entries, we need ability to mark a subset of a SegmentedJournal as deleted. While we could
* treat such delete requests as normal events, this leads to a mismatch between SegmentedJournal indices (as exposed by
* {@link Indexed}) and Akka sequence numbers -- requiring us to potentially perform costly deserialization to find the
* index corresponding to a particular sequence number, or maintain moderately-complex logic and data structures to
* perform that mapping in sub-linear time complexity.
*
*
* Split-file approach allows us to treat sequence numbers and indices as equivalent, without maintaining any explicit
* mapping information. The only additional information we need to maintain is the last deleted sequence number.
*/
abstract sealed class SegmentedJournalActor extends AbstractActor {
abstract static sealed class AsyncMessage {
final Promise promise = Promise.apply();
}
private static final class ReadHighestSequenceNr extends AsyncMessage {
private final long fromSequenceNr;
ReadHighestSequenceNr(final long fromSequenceNr) {
this.fromSequenceNr = fromSequenceNr;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("fromSequenceNr", fromSequenceNr).toString();
}
}
static final class ReplayMessages extends AsyncMessage {
private final long fromSequenceNr;
final long toSequenceNr;
final long max;
final Consumer replayCallback;
ReplayMessages(final long fromSequenceNr,
final long toSequenceNr, final long max, final Consumer replayCallback) {
this.fromSequenceNr = fromSequenceNr;
this.toSequenceNr = toSequenceNr;
this.max = max;
this.replayCallback = requireNonNull(replayCallback);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("fromSequenceNr", fromSequenceNr)
.add("toSequenceNr", toSequenceNr).add("max", max).toString();
}
}
static final class WriteMessages {
private final List requests = new ArrayList<>();
private final List>> results = new ArrayList<>();
Future> add(final AtomicWrite write) {
final var promise = Promise.>apply();
requests.add(write);
results.add(promise);
return promise.future();
}
int size() {
return requests.size();
}
AtomicWrite getRequest(final int index) {
return requests.get(index);
}
void setFailure(final int index, final Exception cause) {
results.get(index).success(Optional.of(cause));
}
void setSuccess(final int index) {
results.get(index).success(Optional.empty());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("requests", requests).toString();
}
}
private static final class DeleteMessagesTo extends AsyncMessage {
final long toSequenceNr;
DeleteMessagesTo(final long toSequenceNr) {
this.toSequenceNr = toSequenceNr;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("toSequenceNr", toSequenceNr).toString();
}
}
// responses == null on success, Exception on failure
record WrittenMessages(WriteMessages message, List