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

com.sleepycat.je.util.LogVerificationInputStream Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je.util;

import java.io.IOException;
import java.io.InputStream;

import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.utilint.LogVerifier;

/**
 * Verifies the checksums in an {@code InputStream} for a log file in a JE
 * {@code Environment}.
 *
 * 

This {@code InputStream} reads input from some other given {@code * InputStream}, and verifies checksums while reading. Its primary intended * use is to verify log files that are being copied as part of a programmatic * backup. It is critical that invalid files are not added to a backup set, * since then both the live environment and the backup will be invalid.

* *

The following example verifies log files as they are being copied. The * {@link DbBackup} class should normally be used to obtain the array of files * to be copied.

* * * *
 *  void copyFiles(final Environment env,
 *                 final String[] fileNames,
 *                 final File destDir,
 *                 final int bufSize)
 *      throws IOException, DatabaseException {
 *
 *      final File srcDir = env.getHome();
 *
 *      for (final String fileName : fileNames) {
 *
 *          final File destFile = new File(destDir, fileName);
 *          final FileOutputStream fos = new FileOutputStream(destFile);
 *
 *          final File srcFile = new File(srcDir, fileName);
 *          final FileInputStream fis = new FileInputStream(srcFile);
 *          final LogVerificationInputStream vis =
 *              new LogVerificationInputStream(env, fis, fileName);
 *
 *          final byte[] buf = new byte[bufSize];
 *
 *          try {
 *              while (true) {
 *                  final int len = vis.read(buf);
 *                  if (len < 0) {
 *                      break;
 *                  }
 *                  fos.write(buf, 0, len);
 *              }
 *          } finally {
 *              fos.close();
 *              vis.close();
 *          }
 *      }
 *  }
 * 
* *

It is important to read the entire underlying input stream until the * end-of-file is reached to detect incomplete entries at the end of the log * file.

* *

Note that {@code mark} and {@code reset} are not supported and {@code * markSupported} returns false. The default {@link InputStream} * implementation of these methods is used.

* * @see DbBackup * @see DbVerifyLog */ public class LogVerificationInputStream extends InputStream { private static final int SKIP_BUF_SIZE = 2048; private final InputStream in; private final LogVerifier verifier; private byte[] skipBuf; /** * Creates a verification input stream. * * @param env the {@code Environment} associated with the log. * * @param in the underlying {@code InputStream} for the log to be read. * * @param fileName the file name of the input stream, for reporting in the * {@code LogVerificationException}. This should be a simple file name of * the form {@code NNNNNNNN.jdb}, where NNNNNNNN is the file number in * hexadecimal format. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ public LogVerificationInputStream(final Environment env, final InputStream in, final String fileName) { this(DbInternal.getNonNullEnvImpl(env), in, fileName, -1L); } /** * Internal constructor. If fileNum is less than zero, it is derived from * fileName. */ LogVerificationInputStream(final EnvironmentImpl envImpl, final InputStream in, final String fileName, final long fileNum) { verifier = new LogVerifier(envImpl, fileName, fileNum); this.in = in; } /** * {@inheritDoc} * *

This method reads the underlying {@code InputStream} and verifies the * contents of the stream.

* * @throws LogVerificationException if a checksum cannot be verified or a * log entry is determined to be invalid by examining its contents. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ @Override public int read() throws IOException { /* * This method will rarely, if ever, be called when reading a file, so * allocating a new byte array is not a performance issue and is the * simplest approach. */ final byte[] b = new byte[1]; final int lenRead = read(b, 0, 1); return (lenRead <= 0) ? lenRead : (b[0] & 0xff); } /** * {@inheritDoc} * *

This method reads the underlying {@code InputStream} and verifies the * contents of the stream.

* * @throws LogVerificationException if a checksum cannot be verified or a * log entry is determined to be invalid by examining its contents. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ @Override public int read(final byte b[]) throws IOException { return read(b, 0, b.length); } /** * {@inheritDoc} * *

This method reads the underlying {@code InputStream} and verifies the * contents of the stream.

* * @throws LogVerificationException if a checksum cannot be verified or a * log entry is determined to be invalid by examining its contents. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ @Override public int read(final byte b[], final int off, final int len) throws IOException { final int lenRead = in.read(b, off, len); if (lenRead <= 0) { if (lenRead < 0) { verifier.verifyAtEof(); } return lenRead; } verifier.verify(b, off, lenRead); return lenRead; } /** * {@inheritDoc} * *

This method reads the underlying {@code InputStream} in order to * skip the required number of bytes and verifies the contents of the * stream. A temporary buffer is allocated lazily for reading.

* * @throws LogVerificationException if a checksum cannot be verified or a * log entry is determined to be invalid by examining its contents. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ @Override public long skip(final long bytesToSkip) throws IOException { if (bytesToSkip <= 0) { return 0; } /* * Like InputStream.skip, we lazily allocate a skip buffer. We must * read the data in order to validate the checksum. Unlike the * InputStream.skip implementation, we cannot use a static buffer * because we do process the data and cannot allow multiple threads to * share the same buffer. */ if (skipBuf == null) { skipBuf = new byte[SKIP_BUF_SIZE]; } long remaining = bytesToSkip; while (remaining > 0) { final int lenRead = read (skipBuf, 0, (int) Math.min(SKIP_BUF_SIZE, remaining)); if (lenRead < 0) { break; } remaining -= lenRead; } return bytesToSkip - remaining; } /** * {@inheritDoc} * *

This method simply performs in.available(). */ @Override public int available() throws IOException { return in.available(); } /** * {@inheritDoc} * *

This method simply performs {@code in.close()}. */ @Override public void close() throws IOException { in.close(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy