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

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

There is a newer version: 0.16.4
Show newest version
/*
 * 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.spi.SnapshotWriter;
import io.zeebe.util.FileUtil;
import org.agrona.BitUtil;
import org.agrona.LangUtil;
import org.slf4j.Logger;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.Arrays;

import static io.zeebe.util.StringUtil.getBytes;


public class FsSnapshotWriter implements SnapshotWriter
{
    public static final Logger LOG = io.zeebe.logstreams.impl.Loggers.LOGSTREAMS_LOGGER;
    protected final FsSnapshotStorageConfiguration config;
    protected final File dataFile;
    protected final File checksumFile;
    protected final FsReadableSnapshot lastSnapshot;

    protected DigestOutputStream dataOutputStream;
    protected BufferedOutputStream checksumOutputStream;

    public FsSnapshotWriter(FsSnapshotStorageConfiguration config, File snapshotFile, File checksumFile, FsReadableSnapshot lastSnapshot)
    {
        this.config = config;
        this.dataFile = snapshotFile;
        this.checksumFile = checksumFile;
        this.lastSnapshot = lastSnapshot;

        initOutputStreams(config, snapshotFile, checksumFile);
    }

    protected void initOutputStreams(FsSnapshotStorageConfiguration config, File snapshotFile, File checksumFile)
    {
        try
        {
            final MessageDigest messageDigest = MessageDigest.getInstance(config.getChecksumAlgorithm());

            final FileOutputStream dataFileOutputStream = new FileOutputStream(snapshotFile);
            final BufferedOutputStream bufferedDataOutputStream = new BufferedOutputStream(dataFileOutputStream);
            dataOutputStream = new DigestOutputStream(bufferedDataOutputStream, messageDigest);

            final FileOutputStream checksumFileOutputStream = new FileOutputStream(checksumFile);
            checksumOutputStream = new BufferedOutputStream(checksumFileOutputStream);

        }
        catch (Exception e)
        {
            abort();
            LangUtil.rethrowUnchecked(e);
        }
    }

    @Override
    public OutputStream getOutputStream()
    {
        return dataOutputStream;
    }

    @Override
    public void commit() throws Exception
    {
        try
        {
            dataOutputStream.close();

            final MessageDigest digest = dataOutputStream.getMessageDigest();

            final byte[] digestBytes = digest.digest();
            final String digestString = BitUtil.toHex(digestBytes);
            final String checksumFileContents = config.checksumContent(digestString, getDataFileName());

            checksumOutputStream.write(getBytes(checksumFileContents));
            checksumOutputStream.close();

            if (lastSnapshot != null)
            {
                LOG.info("Delete last snapshot file {}.", lastSnapshot.getDataFile());
                lastSnapshot.delete();
            }
        }
        catch (Exception e)
        {
            abort();
            LangUtil.rethrowUnchecked(e);
        }
    }

    @Override
    public void abort()
    {
        FileUtil.closeSilently(dataOutputStream);
        FileUtil.closeSilently(checksumOutputStream);
        dataFile.delete();
        checksumFile.delete();
    }

    public File getChecksumFile()
    {
        return checksumFile;
    }

    public File getDataFile()
    {
        return dataFile;
    }

    protected String getDataFileName()
    {
        return dataFile.getName();
    }

    @Override
    public void validateAndCommit(final byte[] checksum) throws Exception
    {
        try
        {
            dataOutputStream.close();
        }
        catch (final Exception ex)
        {
            abort();
            throw ex;
        }

        final byte[] writtenChecksum = dataOutputStream.getMessageDigest().digest();
        if (Arrays.equals(writtenChecksum, checksum))
        {
            commit();
        }
        else
        {
            abort();
            throw new RuntimeException(String.format("Mismatched checksums, expected %s, got %s",
                BitUtil.toHex(checksum), BitUtil.toHex(writtenChecksum)));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy