PersistItStorage.java revision b506a6cd184bd8cf477f7d9a7f968c990f153528
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2014-2015 ForgeRock AS
*/
/** PersistIt database implementation of the {@link Storage} engine. */
public final class PersistItStorage implements Storage, ConfigurationChangeListener<PersistitBackendCfg>,
{
/** The buffer / page size used by the PersistIt storage. */
/** PersistIt implementation of the {@link Cursor} interface. */
private final class CursorImpl implements Cursor
{
private ByteString currentKey;
private ByteString currentValue;
{
}
public void close()
{
// Release immediately because this exchange did not come from the txn cache
}
public ByteString getKey()
{
if (currentKey == null)
{
}
return currentKey;
}
public ByteString getValue()
{
if (currentValue == null)
{
}
return currentValue;
}
public boolean next()
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
public boolean positionToLastKey()
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
public boolean previous()
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
private void clearCurrentKeyAndValue()
{
currentKey = null;
currentValue = null;
}
}
/** PersistIt implementation of the {@link Importer} interface. */
private final class ImporterImpl implements Importer
{
public void close()
{
try
{
}
catch (final Exception e)
{
throw new StorageRuntimeException(e);
}
finally
{
PersistItStorage.this.close();
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
final ByteSequence value)
{
try
{
}
catch (final Exception e)
{
throw new StorageRuntimeException(e);
}
}
}
/** PersistIt implementation of the {@link WriteableStorage} interface. */
private final class StorageImpl implements WriteableStorage
{
final ByteSequence value)
{
try
{
}
catch (final Exception e)
{
throw new StorageRuntimeException(e);
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
{
try
{
ex.removeTree();
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
finally
{
}
}
{
try
{
long count = 0;
{
count++;
}
return count;
}
finally
{
}
}
{
try
{
/*
* Acquire a new exchange for the cursor rather than using a cached
* exchange in order to avoid reentrant accesses to the same tree
* interfering with the cursor position.
*/
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
finally
{
}
}
{
try
{
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
}
{
throw new UnsupportedOperationException();
}
{
try
{
{
{
}
else
{
}
return true;
}
return false;
}
catch (final Exception e)
{
throw new StorageRuntimeException(e);
}
}
{
{
}
}
throws PersistitException
{
{
}
return exchange;
}
public void close()
{
{
}
}
throws PersistitException
{
}
}
{
{
{
}
}
else
{
}
}
private File backendDirectory;
private Configuration dbCfg;
private PersistitBackendCfg config;
private DiskSpaceMonitor diskMonitor;
private MemoryQuota memQuota;
/**
* Creates a new persistit storage with the provided configuration.
*
* @param cfg
* The configuration.
* @param serverContext
* This server instance context
* @throws ConfigException if memory cannot be reserved
*/
// FIXME: should be package private once importer is decoupled.
public PersistItStorage(final PersistitBackendCfg cfg, ServerContext serverContext) throws ConfigException
{
dbCfg = new Configuration();
dbCfg.setVolumeList(asList(new VolumeSpecification(new File(backendDirectory, VOLUME_NAME).getPath(), null,
{
}
else
{
}
cfg.addPersistitChangeListener(this);
}
/** {@inheritDoc} */
public void close()
{
{
try
{
}
catch (final PersistitException e)
{
throw new IllegalStateException(e);
}
}
{
}
else
{
}
}
private BufferPoolConfiguration getBufferPoolCfg()
{
}
/** {@inheritDoc} */
{
try
{
db.initialize();
}
catch (final PersistitException e)
{
throw new StorageRuntimeException(e);
}
// Register as disk space monitor handler
//Register as an AlertGenerator.
}
/** {@inheritDoc} */
{
for (;;)
{
try
{
try
{
return result;
}
catch (final StorageRuntimeException e)
{
{
}
throw e;
}
finally
{
storageImpl.close();
}
}
catch (final RollbackException e)
{
// retry
}
catch (final Exception e)
{
throw e;
}
finally
{
}
}
}
/** {@inheritDoc} */
{
open();
return new ImporterImpl();
}
{
{
{
ch = '_';
}
}
}
/** {@inheritDoc} */
{
for (;;)
{
try
{
try
{
return;
}
catch (final StorageRuntimeException e)
{
{
}
throw e;
}
finally
{
storageImpl.close();
}
}
catch (final RollbackException e)
{
// retry
}
catch (final Exception e)
{
throw e;
}
finally
{
}
}
}
public WriteableStorage getWriteableStorage()
{
return new StorageImpl();
}
public boolean supportsBackupAndRestore()
{
return true;
}
public File getDirectory()
{
}
/** {@inheritDoc} */
public FilenameFilter getFilesToBackupFilter()
{
return new FilenameFilter()
{
{
}
};
}
/**
* inefficient at the moment for simple byte arrays.
*/
{
}
{
return value;
}
{
}
{
{
}
return null;
}
/** {@inheritDoc} */
public boolean isConfigurationChangeAcceptable(PersistitBackendCfg cfg, List<LocalizableMessage> unacceptableReasons)
{
}
/**
* Checks newly created backend has a valid configuration.
* @param cfg the new configuration
* @param unacceptableReasons the list of accumulated errors and their messages
* @param context TODO
* @return true if newly created backend has a valid configuration
*/
public static boolean isConfigurationAcceptable(PersistitBackendCfg cfg, List<LocalizableMessage> unacceptableReasons,
{
{
{
return false;
}
{
return false;
}
}
}
{
{
return false;
}
return true;
}
/**
* Checks a directory exists or can actually be created.
*
* @param backendDir the directory to check for
* @param ccr the list of reasons to return upstream or null if called from setupStorage()
* @param cleanup true if the directory should be deleted after creation
*/
private static void checkDBDirExistsOrCanCreate(File backendDir, ConfigChangeResult ccr, boolean cleanup)
{
if (!backendDir.exists())
{
if(!backendDir.mkdirs())
{
}
if (cleanup)
{
backendDir.delete();
}
}
else if (!backendDir.isDirectory())
{
}
}
/**
* Returns false if directory permissions in the configuration are invalid. Otherwise returns the
* same value as it was passed in.
*
* @param cfg a (possibly new) backend configuration
* @param ccr the current list of change results
* @throws forwards a file exception
*/
{
try
{
// Make sure the mode will allow the server itself access to the database
if(!backendPermission.isOwnerWritable() ||
{
}
}
catch(ConfigException ce)
{
}
}
/**
* Sets files permissions on the backend directory
*
* @param backendDir the directory to setup
* @param curCfg a backend configuration
*/
private void setDBDirPermissions(PersistitBackendCfg curCfg, File backendDir) throws ConfigException
{
// Get the backend database backendDirectory permissions and apply
{
try
{
{
}
}
catch(Exception e)
{
// Log an warning that the permissions were not set.
}
}
}
private static FilePermission decodeDBDirPermissions(PersistitBackendCfg curCfg) throws ConfigException
{
try
{
}
catch (Exception e)
{
}
}
/** {@inheritDoc} */
{
try
{
// Create the directory if it doesn't exist.
{
{
return ccr;
}
ccr.setAdminActionRequired(true);
cfg.getDBDirectory()));
}
{
{
return ccr;
}
}
}
catch (Exception e)
{
}
return ccr;
}
{
}
private void setupStorageFiles() throws ConfigException
{
{
}
{
}
}
public void removeStorageFiles() throws StorageRuntimeException
{
if (!backendDirectory.isDirectory())
{
}
try
{
{
f.delete();
}
}
catch (Exception e)
{
logger.traceException(e);
}
}
public StorageStatus getStorageStatus()
{
{
}
if (diskMonitor.isLowThresholdReached())
{
}
return StorageStatus.working();
}
/** {@inheritDoc} */
}
/** {@inheritDoc} */
}
/** {@inheritDoc} */
}
{
return dm;
}
/** {@inheritDoc} */
public DN getComponentEntryDN() {
}
/** {@inheritDoc} */
public String getClassName() {
return PersistItStorage.class.getName();
}
/** {@inheritDoc} */
{
return alerts;
}
}