org.apache.cassandra.utils.SyncUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-all Show documentation
Show all versions of cassandra-all Show documentation
The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.cassandra.utils;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.MappedByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.cassandra.config.Config;
import com.google.common.base.Preconditions;
import org.apache.cassandra.io.util.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* A wrapper around various mechanisms for syncing files that makes it possible it intercept
* and skip syncing. Useful for unit tests in certain environments where syncs can have outliers
* bad enough to causes tests to run 10s of seconds longer.
*/
public class SyncUtil
{
public static final boolean SKIP_SYNC;
private static final Field mbbFDField;
private static final Field fdClosedField;
private static final Field fdUseCountField;
private static final Logger logger = LoggerFactory.getLogger(SyncUtil.class);
static
{
Field mbbFDFieldTemp = null;
try
{
mbbFDFieldTemp = MappedByteBuffer.class.getDeclaredField("fd");
mbbFDFieldTemp.setAccessible(true);
}
catch (NoSuchFieldException e)
{
}
mbbFDField = mbbFDFieldTemp;
//Java 8
Field fdClosedFieldTemp = null;
try
{
fdClosedFieldTemp = FileDescriptor.class.getDeclaredField("closed");
fdClosedFieldTemp.setAccessible(true);
}
catch (NoSuchFieldException e)
{
}
fdClosedField = fdClosedFieldTemp;
//Java 7
Field fdUseCountTemp = null;
try
{
fdUseCountTemp = FileDescriptor.class.getDeclaredField("useCount");
fdUseCountTemp.setAccessible(true);
}
catch (NoSuchFieldException e)
{
}
fdUseCountField = fdUseCountTemp;
//If skipping syncing is requested by any means then skip them.
boolean skipSyncProperty = Boolean.getBoolean(Config.PROPERTY_PREFIX + "skip_sync");
boolean skipSyncEnv = Boolean.valueOf(System.getenv().getOrDefault("CASSANDRA_SKIP_SYNC", "false"));
SKIP_SYNC = skipSyncProperty || skipSyncEnv;
if (SKIP_SYNC)
{
logger.info("Skip fsync enabled due to property {} and environment {}", skipSyncProperty, skipSyncEnv);
}
}
public static MappedByteBuffer force(MappedByteBuffer buf)
{
Preconditions.checkNotNull(buf);
if (SKIP_SYNC)
{
Object fd = null;
try
{
if (mbbFDField != null)
{
fd = mbbFDField.get(buf);
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
//This is what MappedByteBuffer.force() throws if a you call force() on an umapped buffer
if (mbbFDField != null && fd == null)
throw new UnsupportedOperationException();
return buf;
}
else
{
return buf.force();
}
}
public static void sync(FileDescriptor fd) throws SyncFailedException
{
Preconditions.checkNotNull(fd);
if (SKIP_SYNC)
{
boolean closed = false;
try
{
if (fdClosedField != null)
closed = fdClosedField.getBoolean(fd);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
int useCount = 1;
try
{
if (fdUseCountField != null)
useCount = ((AtomicInteger)fdUseCountField.get(fd)).get();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
if (closed || !fd.valid() || useCount < 0)
throw new SyncFailedException("Closed " + closed + " valid " + fd.valid() + " useCount " + useCount);
}
else
{
fd.sync();
}
}
public static void force(FileChannel fc, boolean metaData) throws IOException
{
Preconditions.checkNotNull(fc);
if (SKIP_SYNC)
{
if (!fc.isOpen())
throw new ClosedChannelException();
}
else
{
fc.force(metaData);
}
}
public static void sync(FileOutputStream fos) throws IOException
{
Preconditions.checkNotNull(fos);
sync(fos.getFD());
}
public static void trySync(int fd)
{
if (SKIP_SYNC)
return;
else
NativeLibrary.trySync(fd);
}
public static void trySyncDir(File dir)
{
if (SKIP_SYNC)
return;
int directoryFD = NativeLibrary.tryOpenDirectory(dir.path());
try
{
trySync(directoryFD);
}
finally
{
NativeLibrary.tryCloseFD(directoryFD);
}
}
}