Java tutorial
// -*- mode:Java; tab-width:2; c-basic-offset:2; indent-tabs-mode:t -*- /** * * Licensed under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * * Implements the Hadoop FS interfaces to allow applications to store * files in Ceph. */ package org.apache.hadoop.fs.ceph; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.util.Progressable; /** * <p> * An {@link OutputStream} for a CephFileSystem and corresponding * Ceph instance. */ public class CephOutputStream extends OutputStream { private static final Log LOG = LogFactory.getLog(CephOutputStream.class); private boolean closed; private CephFS ceph; private int fileHandle; private byte[] buffer; private int bufUsed = 0; /** * Construct the CephOutputStream. * @param conf The FileSystem configuration. * @param fh The Ceph filehandle to connect to. */ public CephOutputStream(Configuration conf, CephFS cephfs, int fh, int bufferSize) { ceph = cephfs; fileHandle = fh; closed = false; buffer = new byte[bufferSize]; } /** Ceph likes things to be closed before it shuts down, *so closing the IOStream stuff voluntarily is good */ protected void finalize() throws Throwable { try { if (!closed) { close(); } } finally { super.finalize(); } } /** * Get the current position in the file. * @return The file offset in bytes. */ public long getPos() throws IOException { return ceph.ceph_getpos(fileHandle); } /** * Write a byte. * @param b The byte to write. * @throws IOException If you have closed the CephOutputStream or the * write fails. */ @Override public synchronized void write(int b) throws IOException { LOG.trace("CephOutputStream.write: writing a single byte to fd " + fileHandle); if (closed) { throw new IOException( "CephOutputStream.write: cannot write " + "a byte to fd " + fileHandle + ": stream closed"); } // Stick the byte in a buffer and write it byte buf[] = new byte[1]; buf[0] = (byte) b; write(buf, 0, 1); return; } /** * Write a byte buffer into the Ceph file. * @param buf the byte array to write from * @param off the position in the file to start writing at. * @param len The number of bytes to actually write. * @throws IOException if you have closed the CephOutputStream, or * if buf is null or off + len > buf.length, or * if the write fails due to a Ceph error. */ @Override public synchronized void write(byte buf[], int off, int len) throws IOException { LOG.trace("CephOutputStream.write: writing " + len + " bytes to fd " + fileHandle); // make sure stream is open if (closed) { throw new IOException("CephOutputStream.write: cannot write " + len + "bytes to fd " + fileHandle + ": stream closed"); } int result; int write; while (len > 0) { write = Math.min(len, buffer.length - bufUsed); try { System.arraycopy(buf, off, buffer, bufUsed, write); } catch (IndexOutOfBoundsException ie) { throw new IOException("CephOutputStream.write: Indices out of bounds: " + "write length is " + len + ", buffer offset is " + off + ", and buffer size is " + buf.length); } catch (ArrayStoreException ae) { throw new IOException( "Uh-oh, CephOutputStream failed to do an array" + " copy due to type mismatch..."); } catch (NullPointerException ne) { throw new IOException("CephOutputStream.write: cannot write " + len + "bytes to fd " + fileHandle + ": buffer is null"); } bufUsed += write; len -= write; off += write; if (bufUsed == buffer.length) { result = ceph.ceph_write(fileHandle, buffer, 0, bufUsed); if (result < 0) { throw new IOException( "CephOutputStream.write: Buffered write of " + bufUsed + " bytes failed!"); } if (result != bufUsed) { throw new IOException("CephOutputStream.write: Wrote only " + result + " bytes of " + bufUsed + " in buffer! Data may be lost or written" + " twice to Ceph!"); } bufUsed = 0; } } return; } /** * Flush the buffered data. * @throws IOException if you've closed the stream or the write fails. */ @Override public synchronized void flush() throws IOException { if (!closed) { if (bufUsed == 0) { return; } int result = ceph.ceph_write(fileHandle, buffer, 0, bufUsed); if (result < 0) { throw new IOException( "CephOutputStream.write: Write of " + bufUsed + "bytes to fd " + fileHandle + " failed"); } if (result != bufUsed) { throw new IOException("CephOutputStream.write: Write of " + bufUsed + "bytes to fd " + fileHandle + "was incomplete: only " + result + " of " + bufUsed + " bytes were written."); } bufUsed = 0; return; } } /** * Close the CephOutputStream. * @throws IOException if Ceph somehow returns an error. In current code it can't. */ @Override public synchronized void close() throws IOException { LOG.trace("CephOutputStream.close:enter"); if (!closed) { flush(); int result = ceph.ceph_close(fileHandle); if (result != 0) { throw new IOException("Close failed!"); } closed = true; LOG.trace("CephOutputStream.close:exit"); } } }