/* dCache - http://www.dcache.org/ * * Copyright (C) 2014 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.nearline.filesystem; import com.google.common.collect.Iterables; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import diskCacheV111.util.CacheException; import diskCacheV111.util.InvalidMessageCacheException; import org.dcache.pool.nearline.AbstractBlockingNearlineStorage; import org.dcache.pool.nearline.spi.FlushRequest; import org.dcache.pool.nearline.spi.RemoveRequest; import org.dcache.pool.nearline.spi.StageRequest; import org.dcache.util.Checksum; import org.dcache.vehicles.FileAttributes; import static com.google.common.base.Preconditions.checkArgument; public abstract class FileSystemNearlineStorage extends AbstractBlockingNearlineStorage { private final ExecutorService executor = Executors.newSingleThreadExecutor(); private Path directory; public FileSystemNearlineStorage(String type, String name) { super(type, name); } /** * Returns a path to the external storage for the give name. */ private Path getExternalPath(String name) { return directory.resolve(name); } @Override protected Executor getFlushExecutor() { return executor; } @Override protected Executor getStageExecutor() { return executor; } @Override protected Executor getRemoveExecutor() { return executor; } @Override protected Set<URI> flush(FlushRequest request) throws IOException, URISyntaxException { Path file = Paths.get(request.getReplicaUri()); flush(file, getExternalPath(file.getFileName().toString())); URI uri = new URI(type, name, '/' + request.getFileAttributes().getPnfsId().getId(), null, null); return Collections.singleton(uri); } @Override protected Set<Checksum> stage(StageRequest request) throws CacheException, IOException { FileAttributes fileAttributes = request.getFileAttributes(); URI location = Iterables.getFirst(getLocations(fileAttributes), null); if (location == null) { throw new CacheException(CacheException.BROKEN_ON_TAPE, "File not on nearline storage: " + fileAttributes.getPnfsId()); } String path = location.getPath(); if (path == null) { throw new InvalidMessageCacheException("Invalid nearline storage URI: " + location); } stage(getExternalPath(path.substring(1)), request.getFile().toPath()); return Collections.emptySet(); } @Override public void remove(RemoveRequest request) throws IOException, InvalidMessageCacheException { String path = request.getUri().getPath(); if (path == null) { throw new InvalidMessageCacheException("Invalid nearline storage URI: " + request.getUri()); } remove(getExternalPath(path.substring(1))); } @Override public void configure(Map<String, String> properties) throws IllegalArgumentException { String directory = properties.get("directory"); checkArgument(directory != null, "directory attribute is required"); this.directory = FileSystems.getDefault().getPath(directory); } @Override public void shutdown() { super.shutdown(); executor.shutdown(); } protected abstract void flush(Path path, Path externalPath) throws IOException; protected abstract void stage(Path externalPath, Path path) throws IOException; protected abstract void remove(Path externalPath) throws IOException; }