org.apache.hadoop.fs.ceph.CephOutputStream.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.fs.ceph.CephOutputStream.java

Source

// -*- 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");
        }
    }
}