diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/PageAwareByteArrayCursor.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/PageAwareByteArrayCursor.java index 64919e5070f3e..beae223856267 100644 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/PageAwareByteArrayCursor.java +++ b/community/index/src/test/java/org/neo4j/index/internal/gbptree/PageAwareByteArrayCursor.java @@ -260,6 +260,12 @@ public void putBytes( byte[] data, int arrayOffset, int length ) current.putBytes( data, arrayOffset, length ); } + @Override + public void putBytes( int bytes, byte value ) + { + current.putBytes( bytes, value ); + } + @Override public short getShort() { diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/PageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/PageCursor.java index 53786ec8bac98..2e0db403da933 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/PageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/PageCursor.java @@ -159,6 +159,10 @@ public abstract class PageCursor implements AutoCloseable */ public abstract void putBytes( byte[] data, int arrayOffset, int length ); + /** + * Set the given number of bytes to the given value, beginning at current offset into the page. + */ + public abstract void putBytes( int bytes, byte value ); /** * Get the signed short at the current page offset, and then increment the offset by one. */ diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/CompositePageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/CompositePageCursor.java index 1fb5bfdf89527..e702391f79e8e 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/CompositePageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/CompositePageCursor.java @@ -324,6 +324,12 @@ public void putBytes( byte[] data, int arrayOffset, int length ) throw new UnsupportedOperationException( "Composite page cursor does not yet support this operation" ); } + @Override + public void putBytes( int bytes, byte value ) + { + throw new UnsupportedOperationException( "Composite page cursor does not yet support this operation" ); + } + @Override public short getShort() { diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/DelegatingPageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/DelegatingPageCursor.java index 3fd335c5c1eac..e872d654cbf31 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/DelegatingPageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/DelegatingPageCursor.java @@ -140,6 +140,12 @@ public void putBytes( byte[] data, int arrayOffset, int length ) delegate.putBytes( data, arrayOffset, length ); } + @Override + public void putBytes( int bytes, byte value ) + { + delegate.putBytes( bytes, value ); + } + @Override public void rewind() { diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java index e98bb0a700460..16d37ec07c660 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java @@ -686,6 +686,17 @@ public void putBytes( byte[] data, int arrayOffset, int length ) offset += length; } + @Override + public void putBytes( int bytes, byte value ) + { + long p = getBoundedPointer( offset, bytes ); + if ( !outOfBounds ) + { + UnsafeUtil.setMemory( p, bytes, value ); + } + offset += bytes; + } + @Override public final short getShort() { diff --git a/community/io/src/test/java/org/neo4j/io/pagecache/ByteArrayPageCursor.java b/community/io/src/test/java/org/neo4j/io/pagecache/ByteArrayPageCursor.java index 0dfb4abd90290..414a8661ab5eb 100644 --- a/community/io/src/test/java/org/neo4j/io/pagecache/ByteArrayPageCursor.java +++ b/community/io/src/test/java/org/neo4j/io/pagecache/ByteArrayPageCursor.java @@ -159,6 +159,14 @@ public void putBytes( byte[] data, int arrayOffset, int length ) buffer.put( data, arrayOffset, length ); } + @Override + public void putBytes( int bytes, byte value ) + { + byte[] byteArray = new byte[bytes]; + Arrays.fill( byteArray, value ); + buffer.put( byteArray ); + } + @Override public short getShort() { diff --git a/community/io/src/test/java/org/neo4j/io/pagecache/PageCacheTest.java b/community/io/src/test/java/org/neo4j/io/pagecache/PageCacheTest.java index 3d061f343aae9..e9a0b3f5baecc 100644 --- a/community/io/src/test/java/org/neo4j/io/pagecache/PageCacheTest.java +++ b/community/io/src/test/java/org/neo4j/io/pagecache/PageCacheTest.java @@ -1696,7 +1696,7 @@ public void pagesAddedWithNextWithPageIdMustBeAccessibleWithNoGrowSpecified() th public void writesOfDifferentUnitsMustHaveCorrectEndianess() throws Exception { configureStandardPageCache(); - try ( PagedFile pagedFile = pageCache.map( file( "a" ), 20 ) ) + try ( PagedFile pagedFile = pageCache.map( file( "a" ), 23 ) ) { try ( PageCursor cursor = pagedFile.io( 0, PF_SHARED_WRITE_LOCK ) ) { @@ -1708,6 +1708,7 @@ public void writesOfDifferentUnitsMustHaveCorrectEndianess() throws Exception cursor.putShort( (short) 41 ); // 12+2 = 14 cursor.putByte( (byte) 41 ); // 14+1 = 15 cursor.putBytes( data ); // 15+5 = 20 + cursor.putBytes( 3, (byte) 47 ); // 20+3 = 23 } try ( PageCursor cursor = pagedFile.io( 0, PF_SHARED_WRITE_LOCK ) ) { @@ -1723,19 +1724,25 @@ public void writesOfDifferentUnitsMustHaveCorrectEndianess() throws Exception cursor.getByte(), // 19 cursor.getByte() // 20 }; + byte d = cursor.getByte(); // 21 + byte e = cursor.getByte(); // 22 + byte f = cursor.getByte(); // 23 cursor.setOffset( 0 ); cursor.putLong( 1 + a ); cursor.putInt( 1 + b ); cursor.putShort( (short) (1 + c) ); - for ( byte d : data ) + for ( byte g : data ) { - d++; - cursor.putByte( d ); + g++; + cursor.putByte( g ); } + cursor.putByte( (byte) (1 + d) ); + cursor.putByte( (byte) (1 + e) ); + cursor.putByte( (byte) (1 + f) ); } } - ByteBuffer buf = ByteBuffer.allocate( 20 ); + ByteBuffer buf = ByteBuffer.allocate( 23 ); try ( StoreChannel channel = fs.open( file( "a" ), OpenMode.READ ) ) { channel.readAll( buf ); @@ -1751,6 +1758,9 @@ public void writesOfDifferentUnitsMustHaveCorrectEndianess() throws Exception assertThat( buf.get(), is( (byte) 45 ) ); assertThat( buf.get(), is( (byte) 46 ) ); assertThat( buf.get(), is( (byte) 47 ) ); + assertThat( buf.get(), is( (byte) 48 ) ); + assertThat( buf.get(), is( (byte) 48 ) ); + assertThat( buf.get(), is( (byte) 48 ) ); } @Test( timeout = SHORT_TIMEOUT_MILLIS ) @@ -2469,6 +2479,8 @@ private void verifyWriteOffsets( PageCursor cursor ) assertThat( cursor.getOffset(), is( 18 ) ); cursor.putBytes( new byte[]{1, 2, 3}, 1, 1 ); assertThat( cursor.getOffset(), is( 19 ) ); + cursor.putBytes( 5, (byte)1 ); + assertThat( cursor.getOffset(), is( 24 ) ); } private void verifyReadOffsets( PageCursor cursor ) @@ -2486,16 +2498,19 @@ private void verifyReadOffsets( PageCursor cursor ) assertThat( cursor.getOffset(), is( 18 ) ); cursor.getBytes( new byte[3], 1, 1 ); assertThat( cursor.getOffset(), is( 19 ) ); + cursor.getBytes( new byte[5] ); + assertThat( cursor.getOffset(), is( 24 ) ); byte[] expectedBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 1, // first; long 0, 0, 0, 1, // second; int 0, 1, // third; short 1, // fourth; byte - 1, 2, 3, // lastly; more bytes - 2 + 1, 2, 3, // fifth; more bytes + 2, // sixth; additional bytes + 1, 1, 1, 1, 1, // lastly; more bytes }; - byte[] actualBytes = new byte[19]; + byte[] actualBytes = new byte[24]; cursor.setOffset( 0 ); cursor.getBytes( actualBytes ); assertThat( actualBytes, byteArray( expectedBytes ) ); @@ -2973,6 +2988,12 @@ public void putBytesBeyondPageEndMustThrow() throws IOException verifyPageBounds( cursor -> cursor.putBytes( bytes ) ); } + @Test( timeout = SHORT_TIMEOUT_MILLIS ) + public void putBytesRepeatedByteBeyondPageEndMustThrow() throws IOException + { + verifyPageBounds( cursor -> cursor.putBytes( 3, (byte) 1 ) ); + } + @Test( timeout = SHORT_TIMEOUT_MILLIS ) public void getBytesBeyondPageEndMustThrow() throws IOException { diff --git a/community/io/src/test/java/org/neo4j/io/pagecache/StubPageCursor.java b/community/io/src/test/java/org/neo4j/io/pagecache/StubPageCursor.java index 5c6f3d83af231..0f3432081a182 100644 --- a/community/io/src/test/java/org/neo4j/io/pagecache/StubPageCursor.java +++ b/community/io/src/test/java/org/neo4j/io/pagecache/StubPageCursor.java @@ -24,6 +24,7 @@ import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.concurrent.ThreadLocalRandom; /** @@ -343,6 +344,14 @@ public void putBytes( byte[] data, int arrayOffset, int length ) } } + @Override + public void putBytes( int bytes, byte value ) + { + byte[] byteArray = new byte[bytes]; + Arrays.fill( byteArray, value ); + putBytes( byteArray, 0, bytes ); + } + @Override public short getShort() {