org.apache.flink.runtime.state.gemini.engine.fs.GeminiDataOutputStream Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.flink.runtime.state.gemini.engine.fs;
import org.apache.flink.core.fs.FSDataOutputStream;
import org.apache.flink.util.Preconditions;
import java.io.DataOutput;
import java.io.IOException;
import java.io.UTFDataFormatException;
/**
* We use the implementation of {@link java.io.DataOutputStream} currently,
* but we may optimize something later.
*/
public class GeminiDataOutputStream extends FSDataOutputStream implements DataOutput {
protected final GeminiOutputStream out;
/**
* The number of bytes written to the data output stream so far.
* If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
*/
protected int written;
/**
* bytearr is initialized on demand by writeUTF.
*/
private byte[] bytearr = null;
/**
* Creates a new data output stream to write data to the specified
* underlying output stream. The counter written
is
* set to zero.
*
* @param out the underlying output stream, to be saved for later
* use.
*/
public GeminiDataOutputStream(GeminiOutputStream out) {
this.out = Preconditions.checkNotNull(out);
}
/**
* Increases the written counter by the specified value
* until it reaches Integer.MAX_VALUE.
*/
private void incCount(int value) {
int temp = written + value;
if (temp < 0) {
temp = Integer.MAX_VALUE;
}
written = temp;
}
/**
* Writes the specified byte (the low eight bits of the argument
* b
) to the underlying output stream. If no exception
* is thrown, the counter written
is incremented by
* 1
.
*
* Implements the write
method of OutputStream
.
*
* @param b the byte
to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public void write(int b) throws IOException {
out.write(b);
incCount(1);
}
/**
* Writes len
bytes from the specified byte array
* starting at offset off
to the underlying output stream.
* If no exception is thrown, the counter written
is
* incremented by len
.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
incCount(len);
}
/**
* Flushes this data output stream. This forces any buffered output
* bytes to be written out to the stream.
*
*
The flush
method of DataOutputStream
* calls the flush
method of its underlying output stream.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void close() throws IOException {
out.close();
}
@Override
public long getPos() throws IOException {
return out.getPos();
}
@Override
public void sync() throws IOException {
out.sync();
}
/**
* Writes a boolean
to the underlying output stream as
* a 1-byte value. The value true
is written out as the
* value (byte)1
; the value false
is
* written out as the value (byte)0
. If no exception is
* thrown, the counter written
is incremented by
* 1
.
*
* @param v a boolean
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeBoolean(boolean v) throws IOException {
out.write(v ? 1 : 0);
incCount(1);
}
/**
* Writes out a byte
to the underlying output stream as
* a 1-byte value. If no exception is thrown, the counter
* written
is incremented by 1
.
*
* @param v a byte
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeByte(int v) throws IOException {
out.write(v);
incCount(1);
}
/**
* Writes a short
to the underlying output stream as two
* bytes, high byte first. If no exception is thrown, the counter
* written
is incremented by 2
.
*
* @param v a short
to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeShort(int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(2);
}
/**
* Writes a char
to the underlying output stream as a
* 2-byte value, high byte first. If no exception is thrown, the
* counter written
is incremented by 2
.
*
* @param v a char
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeChar(int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(2);
}
/**
* Writes an int
to the underlying output stream as four
* bytes, high byte first. If no exception is thrown, the counter
* written
is incremented by 4
.
*
* @param v an int
to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeInt(int v) throws IOException {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(4);
}
private byte[] writeBuffer = new byte[8];
/**
* Writes a long
to the underlying output stream as eight
* bytes, high byte first. In no exception is thrown, the counter
* written
is incremented by 8
.
*
* @param v a long
to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeLong(long v) throws IOException {
writeBuffer[0] = (byte) (v >>> 56);
writeBuffer[1] = (byte) (v >>> 48);
writeBuffer[2] = (byte) (v >>> 40);
writeBuffer[3] = (byte) (v >>> 32);
writeBuffer[4] = (byte) (v >>> 24);
writeBuffer[5] = (byte) (v >>> 16);
writeBuffer[6] = (byte) (v >>> 8);
writeBuffer[7] = (byte) (v >>> 0);
out.write(writeBuffer, 0, 8);
incCount(8);
}
/**
* Converts the float argument to an int
using the
* floatToIntBits
method in class Float
,
* and then writes that int
value to the underlying
* output stream as a 4-byte quantity, high byte first. If no
* exception is thrown, the counter written
is
* incremented by 4
.
*
* @param v a float
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.lang.Float#floatToIntBits(float)
*/
@Override
public final void writeFloat(float v) throws IOException {
writeInt(Float.floatToIntBits(v));
}
/**
* Converts the double argument to a long
using the
* doubleToLongBits
method in class Double
,
* and then writes that long
value to the underlying
* output stream as an 8-byte quantity, high byte first. If no
* exception is thrown, the counter written
is
* incremented by 8
.
*
* @param v a double
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.lang.Double#doubleToLongBits(double)
*/
@Override
public final void writeDouble(double v) throws IOException {
writeLong(Double.doubleToLongBits(v));
}
/**
* Writes out the string to the underlying output stream as a
* sequence of bytes. Each character in the string is written out, in
* sequence, by discarding its high eight bits. If no exception is
* thrown, the counter written
is incremented by the
* length of s
.
*
* @param s a string of bytes to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeBytes(String s) throws IOException {
int len = s.length();
for (int i = 0; i < len; i++) {
out.write((byte) s.charAt(i));
}
incCount(len);
}
/**
* Writes a string to the underlying output stream as a sequence of
* characters. Each character is written to the data output stream as
* if by the writeChar
method. If no exception is
* thrown, the counter written
is incremented by twice
* the length of s
.
*
* @param s a String
value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.DataOutputStream#writeChar(int)
* @see java.io.FilterOutputStream#out
*/
@Override
public final void writeChars(String s) throws IOException {
int len = s.length();
for (int i = 0; i < len; i++) {
int v = s.charAt(i);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
}
incCount(len * 2);
}
/**
* Writes a string to the underlying output stream using
* modified UTF-8
* encoding in a machine-independent manner.
*
*
First, two bytes are written to the output stream as if by the
* writeShort
method giving the number of bytes to
* follow. This value is the number of bytes actually written out,
* not the length of the string. Following the length, each character
* of the string is output, in sequence, using the modified UTF-8 encoding
* for the character. If no exception is thrown, the counter
* written
is incremented by the total number of
* bytes written to the output stream. This will be at least two
* plus the length of str
, and at most two plus
* thrice the length of str
.
*
* @param str a string to be written.
* @exception IOException if an I/O error occurs.
*/
@Override
public final void writeUTF(String str) throws IOException {
writeUTF(str, this);
}
/**
* Writes a string to the specified DataOutput using
* modified UTF-8
* encoding in a machine-independent manner.
*
*
First, two bytes are written to out as if by the writeShort
* method giving the number of bytes to follow. This value is the number of
* bytes actually written out, not the length of the string. Following the
* length, each character of the string is output, in sequence, using the
* modified UTF-8 encoding for the character. If no exception is thrown, the
* counter written
is incremented by the total number of
* bytes written to the output stream. This will be at least two
* plus the length of str
, and at most two plus
* thrice the length of str
.
*
* @param str a string to be written.
* @param out destination to write to
* @return The number of bytes written out.
* @exception IOException if an I/O error occurs.
*/
static int writeUTF(String str, DataOutput out) throws IOException {
int strlen = str.length();
int utflen = 0;
int c, count = 0;
/* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utflen++;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
if (utflen > 65535) {
throw new UTFDataFormatException(
"encoded string too long: " + utflen + " bytes");
}
byte[] bytearr = null;
if (out instanceof GeminiDataOutputStream) {
GeminiDataOutputStream dos = (GeminiDataOutputStream) out;
if (dos.bytearr == null || (dos.bytearr.length < (utflen + 2))) {
dos.bytearr = new byte[(utflen * 2) + 2];
}
bytearr = dos.bytearr;
} else {
bytearr = new byte[utflen + 2];
}
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
int i = 0;
for (i = 0; i < strlen; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) {
break;
}
bytearr[count++] = (byte) c;
}
for (; i < strlen; i++){
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
bytearr[count++] = (byte) c;
} else if (c > 0x07FF) {
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
} else {
bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
out.write(bytearr, 0, utflen + 2);
return utflen + 2;
}
/**
* Returns the current value of the counter written
,
* the number of bytes written to this data output stream so far.
* If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
*
* @return the value of the written
field.
* @see GeminiDataOutputStream#written
*/
public final int size() {
return written;
}
}