New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better support for partial buffer reads/writes in translog infrastructure #6576
Changes from 1 commit
0f3ea59
f311fac
e7d0b6b
0e61af8
63b680f
bb5996c
8790ef0
e061063
2cc2a41
8fe4708
345469b
af02268
18b7e41
8230cd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch 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.elasticsearch.common.io; | ||
|
||
import org.jboss.netty.buffer.ChannelBuffer; | ||
|
||
import java.io.EOFException; | ||
import java.io.IOException; | ||
import java.nio.ByteBuffer; | ||
import java.nio.channels.FileChannel; | ||
import java.nio.channels.GatheringByteChannel; | ||
import java.nio.channels.WritableByteChannel; | ||
|
||
public abstract class Channels { | ||
/** | ||
* The maximum chunk size for reads in bytes | ||
*/ | ||
private static final int READ_CHUNK_SIZE = 16384; | ||
/** | ||
* The maximum chunk size for writes in bytes | ||
*/ | ||
private static final int WRITE_CHUNK_SIZE = 8192; | ||
|
||
/** | ||
* read <i>length</i> bytes from <i>position</i> of a file channel | ||
*/ | ||
public static byte[] readFromFileChannel(FileChannel channel, long position, int length) throws IOException { | ||
byte[] res = new byte[length]; | ||
readFromFileChannel(channel, position, res, 0, length); | ||
return res; | ||
|
||
} | ||
|
||
/** | ||
* read <i>length</i> bytes from <i>position</i> of a file channel | ||
* | ||
* @param channel channel to read from | ||
* @param channelPosition position to read from | ||
* @param dest destination byte array to put data in | ||
* @param destOffset offset in dest to read into | ||
* @param length number of bytes to read | ||
*/ | ||
public static void readFromFileChannel(FileChannel channel, long channelPosition, byte[] dest, int destOffset, int length) throws IOException { | ||
ByteBuffer buffer = ByteBuffer.wrap(dest, destOffset, length); | ||
while (length > 0) { | ||
final int toRead = Math.min(READ_CHUNK_SIZE, length); | ||
buffer.limit(buffer.position() + toRead); | ||
assert buffer.remaining() == toRead; | ||
final int i = channel.read(buffer, channelPosition); | ||
if (i < 0) { // be defensive here, even though we checked before hand, something could have changed | ||
throw new EOFException("read past EOF. pos [" + channelPosition + "] chunkLen: [" + toRead + "] end: [" + channel.size() + "]"); | ||
} | ||
assert i > 0 : "FileChannel.read with non zero-length bb.remaining() must always read at least one byte (FileChannel is in blocking mode, see spec of ReadableByteChannel)"; | ||
channelPosition += i; | ||
length -= i; | ||
} | ||
assert length == 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you debug this you really wanna know the length.... maybe add a msg to it? |
||
} | ||
|
||
public static void writeToChannel(ChannelBuffer source, int sourceIndex, int length, GatheringByteChannel channel) throws IOException { | ||
while (length > 0) { | ||
int written = source.getBytes(sourceIndex, channel, length); | ||
sourceIndex += written; | ||
length -= written; | ||
} | ||
assert length == 0; | ||
} | ||
|
||
public static void writeToChannel(byte[] source, int offset, int length, WritableByteChannel channel) throws IOException { | ||
int toWrite = Math.min(length, WRITE_CHUNK_SIZE); | ||
ByteBuffer buffer = ByteBuffer.wrap(source, offset, toWrite); | ||
int written = channel.write(buffer); | ||
length -= written; | ||
while (length > 0) { | ||
toWrite = Math.min(length, WRITE_CHUNK_SIZE); | ||
buffer.limit(buffer.position() + toWrite); | ||
written = channel.write(buffer); | ||
length -= written; | ||
} | ||
assert length == 0; | ||
} | ||
|
||
public static void writeToChannel(ByteBuffer byteBuffer, WritableByteChannel channel) throws IOException { | ||
do { | ||
channel.write(byteBuffer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure, but I think we need to chunk this write as well, or the JVM could allocate a big threadlocal buffer that hangs around... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. If the ByteBuffer is not a direct buffer, we should chunk. Maybe check if it is direct and chunk only then. |
||
} | ||
while (byteBuffer.position() != byteBuffer.limit()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a real unittest for this class? I mean it's tested well but I'd love to have a dedicated test for that really hammers it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this class final with a default private ctor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final I get. Wondering why the default private ctor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah - I get it :) final to prevent extending, private ctor to replace the abstract. Coming up.