/* * dCache - http://www.dcache.org/ * * Copyright (C) 2016 Deutsches Elektronen-Synchrotron * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.dcache.pool.repository.meta.db; import com.sleepycat.collections.StoredMap; import com.sleepycat.je.DatabaseException; import com.sleepycat.je.EnvironmentConfig; import com.sleepycat.je.EnvironmentFailureException; import com.sleepycat.je.Transaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Properties; import diskCacheV111.util.CacheException; import diskCacheV111.util.PnfsId; import diskCacheV111.vehicles.StorageInfo; import dmg.cells.nucleus.EnvironmentAware; import org.dcache.pool.movers.IoMode; import org.dcache.pool.repository.ReplicaStore; import org.dcache.pool.repository.RepositoryChannel; import org.dcache.util.ConfigurationMapFactoryBean; /** * Base class for BerkeleyDB backed ReplicaStore implementations. * * The database is stored in a subdirectory of the pool directory * called 'meta'. * * The cache repository entries generated by this store fetch storage * info from the database on demand. */ public abstract class AbstractBerkeleyDBReplicaStore implements ReplicaStore, EnvironmentAware { protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractBerkeleyDBReplicaStore.class); protected static final String DIRECTORY_NAME = "meta"; protected final boolean readOnly; /** * Berkeley DB configuration properties. */ private final Properties properties = new Properties(); /** * Directory containing the database. */ protected final Path dir; /** * The BerkeleyDB database to use. */ private ReplicaStoreDatabase database; /** * The BerkeleyDB database to use. */ protected ReplicaStoreView views; public AbstractBerkeleyDBReplicaStore(Path directory, boolean readOnly) throws IOException { this.readOnly = readOnly; dir = directory.resolve(DIRECTORY_NAME); if (!Files.exists(dir)) { Files.createDirectory(dir); } else if (!Files.isDirectory(dir)) { throw new FileNotFoundException("No such directory: " + dir); } } @Override public void setEnvironment(Map<String, Object> environment) { ConfigurationMapFactoryBean factory = new ConfigurationMapFactoryBean(); factory.setEnvironment(environment); factory.setPrefix("pool.plugins.meta.db"); factory.buildMap(); properties.clear(); properties.putAll(factory.getObject()); } @Override public void init() throws CacheException { try { database = new ReplicaStoreDatabase(properties, dir.toFile(), readOnly); views = new ReplicaStoreView(database); } catch (EnvironmentFailureException e) { throw new CacheException(CacheException.PANIC, "Failed to open Berkeley DB database. When upgrading to " + "dCache 2.6, it may be necessary to run the /usr/sbin/dcache-pool-meta-preupgrade utility " + "before starting the pool. If that does not resolve the problem, you should contact " + "support@dcache.org", e); } } /** * Returns a database backed map of all StorageInfo objects. */ StoredMap<String,StorageInfo> getStorageInfoMap() { return views.getStorageInfoMap(); } /** * Returns a database backed map of all state objects. */ StoredMap<String,CacheRepositoryEntryState> getStateMap() { return views.getStateMap(); } /** Closes the database. */ @Override public void close() { try { database.close(); } catch (DatabaseException e) { LOGGER.error("Ignored: Could not close database: " + e.getMessage()); } } @Override public synchronized boolean isOk() { Path tmp = dir.resolve(".repository_is_ok"); try { Files.deleteIfExists(tmp); Files.createFile(tmp); if (database.isFailed()) { return false; } return true; } catch (IOException e) { LOGGER.error("Failed to touch " + tmp + ": " + e.getMessage()); return false; } } public boolean isValid() { return database.getEnvironment().isValid(); } public EnvironmentConfig getConfig() { return database.getEnvironment().getConfig(); } public Transaction beginTransaction() { return database.getEnvironment().beginTransaction(null, null); } public abstract void setLastModifiedTime(PnfsId pnfsId, long time) throws IOException; public abstract long getFileSize(PnfsId pnfsId) throws IOException; public abstract URI getUri(PnfsId pnfsId); public abstract RepositoryChannel openChannel(PnfsId pnfsId, IoMode mode) throws IOException; }