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

io.zeebe.logstreams.impl.snapshot.fs.FsSnapshotStorage Maven / Gradle / Ivy

/*
 * Copyright © 2017 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.zeebe.logstreams.impl.snapshot.fs;

import io.zeebe.logstreams.impl.Loggers;
import io.zeebe.logstreams.spi.SnapshotMetadata;
import io.zeebe.logstreams.spi.SnapshotStorage;
import io.zeebe.util.FileUtil;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger;

public class FsSnapshotStorage implements SnapshotStorage {
  public static final Logger LOG = Loggers.LOGSTREAMS_LOGGER;

  protected final FsSnapshotStorageConfiguration cfg;

  public FsSnapshotStorage(FsSnapshotStorageConfiguration cfg) {
    this.cfg = cfg;
  }

  @Override
  public FsReadableSnapshot getLastSnapshot(final String name) {
    final File rootFile = new File(cfg.getRootPath());
    final List snapshotFiles =
        Arrays.asList(rootFile.listFiles(file -> cfg.matchesSnapshotFileNamePattern(file, name)));
    FsReadableSnapshot snapshot = null;

    if (!snapshotFiles.isEmpty()) {
      final List committedSortedSnapshotFiles =
          snapshotFiles
              .stream()
              .filter((f) -> isCommitted(f, name))
              .sorted(Comparator.comparingLong((f) -> position(f, name)))
              .collect(Collectors.toList());

      if (!committedSortedSnapshotFiles.isEmpty()) {
        final File snapshotFile = committedSortedSnapshotFiles.get(0);
        final long logPosition = position(snapshotFile, name);
        final String checksumFileName = cfg.checksumFileName(name, logPosition);
        final File checksumFile = new File(checksumFileName);

        snapshot = new FsReadableSnapshot(cfg, snapshotFile, checksumFile, logPosition);
      }
    }

    return snapshot;
  }

  @Override
  public FsSnapshotWriter createSnapshot(String name, long logPosition) throws Exception {
    final FsReadableSnapshot lastSnapshot = getLastSnapshot(name);

    final String snapshotFileName = cfg.snapshotFileName(name, logPosition);
    final String checksumFileName = cfg.checksumFileName(name, logPosition);

    final File snapshotFile = new File(snapshotFileName);
    final File checksumFile = new File(checksumFileName);

    if (snapshotFile.exists()) {
      throw new RuntimeException(
          String.format(
              "Cannot write snapshot %s, file already exists.", snapshotFile.getAbsolutePath()));
    }

    try {
      snapshotFile.createNewFile();
    } catch (IOException e) {
      FileUtil.deleteFile(snapshotFile);
      throw e;
    }

    return new FsSnapshotWriter(cfg, snapshotFile, checksumFile, lastSnapshot);
  }

  @Override
  public List listSnapshots() {
    final File rootFile = new File(cfg.getRootPath());
    final File[] snapshotFiles = rootFile.listFiles(cfg::isSnapshotFile);
    final ArrayList snapshots = new ArrayList<>();

    if (snapshotFiles != null) {
      snapshots.ensureCapacity(snapshotFiles.length);
      for (final File snapshotFile : snapshotFiles) {
        final String snapshotName = cfg.getSnapshotNameFromFileName(snapshotFile.getName());

        if (isCommitted(snapshotFile, snapshotName)) {
          final File checksumFile = getChecksumFile(snapshotFile, snapshotName);
          final long logPosition = position(snapshotFile, snapshotName);
          try {
            final SnapshotMetadata snapshotMetadata =
                new FsSnapshotMetadata(cfg, snapshotFile, checksumFile, logPosition);
            snapshots.add(snapshotMetadata);
          } catch (final Exception ex) {
            LOG.error("Failed to read snapshot metadata", ex);
          }
        }
      }
    }

    return snapshots;
  }

  @Override
  public boolean snapshotExists(String name, long logPosition) {
    final File snapshotFile = new File(cfg.snapshotFileName(name, logPosition));
    return Files.exists(snapshotFile.toPath()) && isCommitted(snapshotFile, name);
  }

  protected long position(File file, String snapshotName) {
    return cfg.getPositionOfSnapshotFile(file, snapshotName);
  }

  private File getChecksumFile(final File snapshotFile, final String snapshotName) {
    final long logPosition = position(snapshotFile, snapshotName);
    final String checksumFileName = cfg.checksumFileName(snapshotName, logPosition);
    return new File(checksumFileName);
  }

  private boolean isCommitted(final File snapshotFile, final String name) {
    final File checksumFile = getChecksumFile(snapshotFile, name);
    return checksumFile.exists();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy