/*
* 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.ceph;
import org.dcache.rados4j.RadosException;
import org.dcache.rados4j.Rbd;
import org.dcache.rados4j.RbdImage;
import java.io.IOException;
import java.io.SyncFailedException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import org.dcache.pool.repository.RepositoryChannel;
/**
* CEPH back-ended implementation of {@link RepositoryChannel}.
*
* Uses CEPH's block device image interface to store the data.
*/
public class CephRepositoryChannel implements RepositoryChannel {
private RbdImage rbdImage;
private final boolean rdOnly;
private long size;
private long offset = 0;
public CephRepositoryChannel(Rbd rbd, String name, String mode) throws RadosException {
switch (mode) {
case "rw":
case "rwd":
case "rws":
// REVISIT: we do not create image here as it already created by CephFileStore.
//rbd.create(name, 0);
rbdImage = rbd.open(name);
rdOnly = false;
size = 0;
break;
case "r":
rbdImage = rbd.openReadOnly(name);
rdOnly = true;
size = rbdImage.stat().obj_size.get();
break;
default:
throw new IllegalArgumentException("Illegal mode: " + mode);
}
}
@Override
public synchronized long position() throws IOException {
return offset;
}
@Override
public synchronized RepositoryChannel position(long position) throws IOException {
if (rdOnly) {
offset = Math.min(size, position);
} else {
offset = position;
if (offset > size) {
this.resize(size);
}
}
return this;
}
@Override
public synchronized long size() throws IOException {
return size;
}
@Override
public synchronized int write(ByteBuffer src, long position) throws IOException {
if (position + src.remaining() > size) {
this.resize(position + src.remaining());
}
return rbdImage.write(src, position);
}
@Override
public int read(ByteBuffer dst, long position) throws IOException {
// CEPH can't read beyond image size
if (position >= size) {
return -1;
}
return rbdImage.read(dst, position);
}
private void resize(long size) throws RadosException {
rbdImage.resize(size);
this.size = size;
}
@Override
public synchronized RepositoryChannel truncate(long size) throws IOException {
if (this.size < size) {
this.resize(size);
}
return this;
}
@Override
public void sync() throws SyncFailedException, IOException {
// NOP
}
@Override
public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public long write(ByteBuffer[] srcs) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public synchronized int write(ByteBuffer src) throws IOException {
int n = this.write(src, offset);
offset += n;
return n;
}
@Override
public synchronized boolean isOpen() {
return rbdImage != null;
}
@Override
public synchronized void close() throws IOException {
rbdImage.close();
rbdImage = null;
}
@Override
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public long read(ByteBuffer[] dsts) throws IOException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public synchronized int read(ByteBuffer dst) throws IOException {
int n = this.read(dst, offset);
if (n < 0) {
return n;
}
offset += n;
return n;
}
}