現在bytebufの編集中にすべてのバイトが移動する必要がある最悪の場合には、我々はCompositeByteBuf
は我々が編集し、必要に応じて動き回ることができコンポーネントを持っているという事実を利用することができないという欠点があります。
私たちは、基本的に次のステップを実装する:
複数bytebuf s inside a
CompositeByteBuf`があるかもしれませんので、我々は、変更したいBUFのインデックスを検索したいです。挿入でありますとき
、これらの方法は、場合には正しく動作しません。私たちはこれを実行するため
ByteBuf
は以下のメソッドを提供しますこの文字列の最後は、技術的には元のバッファの範囲外であるため、特別なケースを追加する必要がありました。
これらの場合、実際にゼロコピーで作業できるため、複数のバッファの境界に正確に挿入する特殊なケースを実装します。
- 分割インデックスがbytebufの真ん中にある場合、それを分割して2つの別々のバッファーとして追加する必要があります。
- 私たちは、上記のフローを使用してfor some reason this doesn't happen by default.
、複合の作家のインデックスを更新する必要があり、我々は次のコードを作成することができます。このコードは非常に複雑であるので
public static void insertString(CompositeByteBuf buffer, int index, ByteBuf insertion) {
try {
if (buffer == null) {
throw new NullPointerException("buffer");
}
if (insertion == null) {
throw new NullPointerException("insertion");
}
if (buffer.readableBytes() < index) {
throw new IllegalArgumentException("buffer.readableBytes() < index: "
+ buffer.readableBytes() + " < " + index);
}
// Start by checking the offset where we need to inject the insertion
int injectionBufOffset;
int injectionByteOffset;
if (index == buffer.readableBytes()) {
injectionBufOffset = buffer.numComponents();
injectionByteOffset = 0;
} else {
injectionBufOffset = buffer.toComponentIndex(index);
injectionByteOffset = index - buffer.toByteIndex(injectionBufOffset);
}
// Optimalize in the case of offset 0
if (injectionByteOffset == 0) {
buffer.addComponent(injectionBufOffset, insertion.retain());
buffer.writerIndex(buffer.writerIndex() + insertion.readableBytes());
return;
}
// Do the split technique
ByteBuf toSplit = buffer.internalComponent(injectionBufOffset).retain();
try {
buffer.removeComponent(injectionBufOffset);
buffer.addComponent(injectionBufOffset + 0,
toSplit.readSlice(injectionByteOffset).retain());
buffer.addComponent(injectionBufOffset + 1, insertion.retain());
buffer.addComponent(injectionBufOffset + 2,
toSplit.retain());
buffer.writerIndex(buffer.writerIndex() + insertion.readableBytes());
} finally {
ReferenceCountUtil.release(toSplit);
}
} finally {
if (insertion != null) {
ReferenceCountUtil.release(insertion);
}
}
}
を、我々はまたしたいですしたがって、適切にテストされているかどうかを確認するために、ユニットテスト(JUnit)が必要です:
import static test.NettySplit.insertString;
public class NettySplitTest {
CompositeByteBuf buffer;
ByteBuf test;
private void addByteBuf(CompositeByteBuf target, ByteBuf source) {
target.addComponent(source);
target.writerIndex(target.writerIndex() + source.readableBytes());
}
@Before
public void before() {
buffer = ByteBufAllocator.DEFAULT.compositeBuffer();
}
@After
public void after() {
ReferenceCountUtil.release(buffer);
buffer = null;
ReferenceCountUtil.release(test);
test = null;
}
@Test
public void testSplitting() {
addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3}));
insertString(buffer, 2, Unpooled.wrappedBuffer(new byte[]{5}));
test = Unpooled.wrappedBuffer(new byte[]{0, 1, 5, 2, 3});
assertEquals(test, buffer);
}
@Test
public void testInsertionStart() {
addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3}));
insertString(buffer, 0, Unpooled.wrappedBuffer(new byte[]{5}));
test = Unpooled.wrappedBuffer(new byte[]{5, 0, 1, 2, 3});
assertEquals(test, buffer);
}
@Test
public void testInsertionEnd() {
addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3}));
insertString(buffer, 4, Unpooled.wrappedBuffer(new byte[]{5}));
test = Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3, 5});
assertEquals(test, buffer);
}
@Test
public void testInsertionSplitEnd() {
addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3}));
addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3}));
insertString(buffer, 6, Unpooled.wrappedBuffer(new byte[]{5}));
test = Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3, 0, 1, 5, 2, 3});
assertEquals(test, buffer);
}
}
ワウ、今私はそれを理解することができないと感じていません私自身。それでも、私の本能が正しいことを知り、それを効率的に行うことができます。思慮深く答えてくれてありがとう! –