package org.dcache.chimera.nfsv41.mover; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.ByteBuffer; import org.dcache.nfs.ChimeraNFSException; import org.dcache.nfs.nfsstat; import org.dcache.nfs.status.NfsIoException; import org.dcache.nfs.v4.AbstractNFSv4Operation; import org.dcache.nfs.v4.CompoundContext; import org.dcache.nfs.v4.NFSv4Defaults; import org.dcache.nfs.v4.xdr.READ4res; import org.dcache.nfs.v4.xdr.READ4resok; import org.dcache.nfs.v4.xdr.nfs_argop4; import org.dcache.nfs.v4.xdr.nfs_opnum4; import org.dcache.nfs.v4.xdr.nfs_resop4; import org.dcache.pool.repository.RepositoryChannel; public class EDSOperationREAD extends AbstractNFSv4Operation { private static final Logger _log = LoggerFactory.getLogger(EDSOperationREAD.class.getName()); // Bind a direct buffer to each thread. private static final ThreadLocal<ByteBuffer> BUFFERS = new ThreadLocal<ByteBuffer>() { @Override protected ByteBuffer initialValue() { return ByteBuffer.allocateDirect((int)NFSv4Defaults.NFS4_MAXIOBUFFERSIZE); } }; private final NFSv4MoverHandler _moverHandler; public EDSOperationREAD(nfs_argop4 args, NFSv4MoverHandler moverHandler) { super(args, nfs_opnum4.OP_READ); _moverHandler = moverHandler; } @Override public void process(CompoundContext context, nfs_resop4 result) { final READ4res res = result.opread; try { long offset = _args.opread.offset.value; int count = _args.opread.count.value; NfsMover mover = _moverHandler.getOrCreateMover(context.getRemoteSocketAddress(), _args.opread.stateid, context.currentInode().toNfsHandle()); if(mover == null) { /* * return IO error instead of BadStateidException to avoid state recovery. * The client will fall back to IO through MDS. */ throw new NfsIoException("No mover associated with given stateid: " + _args.opread.stateid); } mover.attachSession(context.getSession()); ByteBuffer bb = BUFFERS.get(); bb.clear().limit(count); RepositoryChannel fc = mover.getMoverChannel(); bb.rewind(); int bytesRead = fc.read(bb, offset); res.status = nfsstat.NFS_OK; res.resok4 = new READ4resok(); res.resok4.data = bb; if( bytesRead == -1 || offset + bytesRead == fc.size() ) { res.resok4.eof = true; } _log.debug("MOVER: {}@{} read, {} requested.", bytesRead, offset, _args.opread.count.value); }catch(ChimeraNFSException he) { res.status = he.getStatus(); _log.debug(he.getMessage()); }catch(IOException ioe) { _log.error("DSREAD: ", ioe); res.status = nfsstat.NFSERR_IO; }catch(Exception e) { _log.error("DSREAD: ", e); res.status = nfsstat.NFSERR_SERVERFAULT; } } }