diff --git a/community/common/src/main/java/org/neo4j/memory/GlobalMemoryTracker.java b/community/common/src/main/java/org/neo4j/memory/GlobalMemoryTracker.java
new file mode 100644
index 0000000000000..c1e578f03bfaa
--- /dev/null
+++ b/community/common/src/main/java/org/neo4j/memory/GlobalMemoryTracker.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+import java.util.concurrent.atomic.LongAdder;
+
+/**
+ * Global memory tracker that can be used in a global multi threaded context to record
+ * allocation and de-allocation of native memory.
+ * @see org.neo4j.memory.MemoryAllocationTracker
+ * @see MemoryTracker
+ */
+public class GlobalMemoryTracker implements MemoryTracker, MemoryAllocationTracker
+{
+ private LongAdder longAdder = new LongAdder();
+
+ public static final GlobalMemoryTracker INSTANCE = new GlobalMemoryTracker();
+
+ private GlobalMemoryTracker()
+ {
+ }
+
+ @Override
+ public long usedDirectMemory()
+ {
+ return longAdder.sum();
+ }
+
+ @Override
+ public void allocate( long allocatedBytes )
+ {
+ longAdder.add( allocatedBytes );
+ }
+
+ @Override
+ public void deallocate( long deAllocatedBytes )
+ {
+ longAdder.add( -deAllocatedBytes );
+ }
+}
diff --git a/community/common/src/main/java/org/neo4j/memory/LocalMemoryTracker.java b/community/common/src/main/java/org/neo4j/memory/LocalMemoryTracker.java
new file mode 100644
index 0000000000000..91755b39bd6e2
--- /dev/null
+++ b/community/common/src/main/java/org/neo4j/memory/LocalMemoryTracker.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+/**
+ * Memory allocation tracker that can be used in local context that required
+ * tracking of memory that is independent from global.
+ * All allocations/de-allocation reported to this trackers also will be reported to global tracker transparently.
+ */
+public class LocalMemoryTracker implements MemoryTracker, MemoryAllocationTracker
+{
+ private long allocatedBytes;
+ private GlobalMemoryTracker globalTracker = GlobalMemoryTracker.INSTANCE;
+
+ @Override
+ public void allocate( long allocatedBytes )
+ {
+ globalTracker.allocate( allocatedBytes );
+ this.allocatedBytes += allocatedBytes;
+ }
+
+ @Override
+ public void deallocate( long deallocatedBytes )
+ {
+ globalTracker.deallocate( deallocatedBytes );
+ this.allocatedBytes -= deallocatedBytes;
+ }
+
+ /**
+ * @return number of locally used bytes.
+ */
+ @Override
+ public long usedDirectMemory()
+ {
+ return allocatedBytes;
+ }
+}
diff --git a/community/common/src/main/java/org/neo4j/memory/MemoryAllocationTracker.java b/community/common/src/main/java/org/neo4j/memory/MemoryAllocationTracker.java
new file mode 100644
index 0000000000000..a83651d250a05
--- /dev/null
+++ b/community/common/src/main/java/org/neo4j/memory/MemoryAllocationTracker.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+/**
+ * Memory allocation tracker that tracks bytes allocation and de-allocation
+ */
+public interface MemoryAllocationTracker
+{
+ /**
+ * Record allocation of bytes
+ * @param allocatedBytes number of allocated bytes
+ */
+ void allocate( long allocatedBytes );
+
+ /**
+ * Record de-allocation of bytes
+ * @param deAllocatedBytes number of de0allocated bytes
+ */
+ void deallocate( long deAllocatedBytes );
+}
diff --git a/community/common/src/main/java/org/neo4j/memory/MemoryTracker.java b/community/common/src/main/java/org/neo4j/memory/MemoryTracker.java
new file mode 100644
index 0000000000000..c5710f1b7cb34
--- /dev/null
+++ b/community/common/src/main/java/org/neo4j/memory/MemoryTracker.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+/**
+ * Tracker that capable to report number of allocated bytes.
+ * @see MemoryAllocationTracker
+ */
+public interface MemoryTracker
+{
+ /**
+ * @return number of bytes of direct memory that are used
+ */
+ long usedDirectMemory();
+}
diff --git a/community/common/src/test/java/org/neo4j/memory/GlobalMemoryTrackerTest.java b/community/common/src/test/java/org/neo4j/memory/GlobalMemoryTrackerTest.java
new file mode 100644
index 0000000000000..4b7933a33ca23
--- /dev/null
+++ b/community/common/src/test/java/org/neo4j/memory/GlobalMemoryTrackerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class GlobalMemoryTrackerTest
+{
+
+ @Test
+ public void trackMemoryAllocations()
+ {
+ long initialUsedMemory = GlobalMemoryTracker.INSTANCE.usedDirectMemory();
+ GlobalMemoryTracker.INSTANCE.allocate( 10 );
+ GlobalMemoryTracker.INSTANCE.allocate( 20 );
+ GlobalMemoryTracker.INSTANCE.allocate( 40 );
+ assertEquals( 70, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
+ }
+
+ @Test
+ public void trackMemoryDeallocations()
+ {
+ long initialUsedMemory = GlobalMemoryTracker.INSTANCE.usedDirectMemory();
+ GlobalMemoryTracker.INSTANCE.allocate( 100 );
+ assertEquals( 100, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
+
+ GlobalMemoryTracker.INSTANCE.deallocate( 20 );
+ assertEquals( 80, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
+
+ GlobalMemoryTracker.INSTANCE.deallocate( 40 );
+ assertEquals( 40, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
+ }
+}
diff --git a/community/common/src/test/java/org/neo4j/memory/LocalMemoryTrackerTest.java b/community/common/src/test/java/org/neo4j/memory/LocalMemoryTrackerTest.java
new file mode 100644
index 0000000000000..68148778025a0
--- /dev/null
+++ b/community/common/src/test/java/org/neo4j/memory/LocalMemoryTrackerTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2002-2018 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.memory;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class LocalMemoryTrackerTest
+{
+ @Test
+ public void trackMemoryAllocations()
+ {
+ LocalMemoryTracker memoryTracker = new LocalMemoryTracker();
+ memoryTracker.allocate( 10 );
+ memoryTracker.allocate( 20 );
+ memoryTracker.allocate( 40 );
+ assertEquals( 70, memoryTracker.usedDirectMemory());
+ }
+
+ @Test
+ public void trackMemoryDeallocations()
+ {
+ LocalMemoryTracker memoryTracker = new LocalMemoryTracker();
+ memoryTracker.allocate( 100 );
+ assertEquals( 100, memoryTracker.usedDirectMemory() );
+
+ memoryTracker.deallocate( 20 );
+ assertEquals( 80, memoryTracker.usedDirectMemory() );
+
+ memoryTracker.deallocate( 40 );
+ assertEquals( 40, memoryTracker.usedDirectMemory() );
+ }
+
+ @Test
+ public void localMemoryTrackerPropagatesAllocationsToGlobalTracker()
+ {
+ GlobalMemoryTracker globalMemoryTracker = GlobalMemoryTracker.INSTANCE;
+ long initialGlobalUsage = globalMemoryTracker.usedDirectMemory();
+ LocalMemoryTracker memoryTracker = new LocalMemoryTracker();
+
+ memoryTracker.allocate( 100 );
+ assertEquals( 100, memoryTracker.usedDirectMemory() );
+ assertEquals( 100, globalMemoryTracker.usedDirectMemory() - initialGlobalUsage );
+
+ memoryTracker.deallocate( 50 );
+ assertEquals( 50, memoryTracker.usedDirectMemory() );
+ assertEquals( 50, globalMemoryTracker.usedDirectMemory() - initialGlobalUsage );
+ }
+
+}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/ResourceTypesIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/ResourceTypesIT.java
index 0ab06fc871b35..590493af02eed 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/ResourceTypesIT.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/ResourceTypesIT.java
@@ -23,6 +23,7 @@
import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongLongMap;
+import org.neo4j.memory.GlobalMemoryTracker;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@@ -40,7 +41,7 @@ public class ResourceTypesIT
public void indexEntryHashing()
{
int collisions = 0;
- try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( 35_000_000 ) )
+ try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( 35_000_000, GlobalMemoryTracker.INSTANCE ) )
{
int labelIdCount = 50;
diff --git a/community/kernel/src/test/java/org/neo4j/test/FakeCpuClock.java b/community/kernel/src/test/java/org/neo4j/test/FakeCpuClock.java
index 71c8cb6041bbb..42d186b2436a3 100644
--- a/community/kernel/src/test/java/org/neo4j/test/FakeCpuClock.java
+++ b/community/kernel/src/test/java/org/neo4j/test/FakeCpuClock.java
@@ -19,14 +19,15 @@
*/
package org.neo4j.test;
-import java.util.concurrent.TimeUnit;
-
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.concurrent.TimeUnit;
+
import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongLongMap;
+import org.neo4j.memory.GlobalMemoryTracker;
import org.neo4j.resources.CpuClock;
public class FakeCpuClock extends CpuClock implements TestRule
@@ -39,7 +40,7 @@ public long cpuTimeNanos( long threadId )
return -1;
}
};
- private final PrimitiveLongLongMap cpuTimes = Primitive.offHeapLongLongMap();
+ private final PrimitiveLongLongMap cpuTimes = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE );
@Override
public long cpuTimeNanos( long threadId )
diff --git a/community/kernel/src/test/java/org/neo4j/test/FakeHeapAllocation.java b/community/kernel/src/test/java/org/neo4j/test/FakeHeapAllocation.java
index 69eee9dd92565..c5a6776fcfb3b 100644
--- a/community/kernel/src/test/java/org/neo4j/test/FakeHeapAllocation.java
+++ b/community/kernel/src/test/java/org/neo4j/test/FakeHeapAllocation.java
@@ -24,6 +24,7 @@
import org.junit.runners.model.Statement;
import org.neo4j.collection.primitive.PrimitiveLongLongMap;
+import org.neo4j.memory.GlobalMemoryTracker;
import org.neo4j.resources.HeapAllocation;
import static java.lang.Thread.currentThread;
@@ -31,7 +32,7 @@
public class FakeHeapAllocation extends HeapAllocation implements TestRule
{
- private final PrimitiveLongLongMap allocation = offHeapLongLongMap();
+ private final PrimitiveLongLongMap allocation = offHeapLongLongMap( GlobalMemoryTracker.INSTANCE );
@Override
public long allocatedBytes( long threadId )
diff --git a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/Primitive.java b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/Primitive.java
index d1dee17285fe4..767eb00572c8e 100644
--- a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/Primitive.java
+++ b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/Primitive.java
@@ -36,6 +36,7 @@
import org.neo4j.collection.primitive.hopscotch.PrimitiveLongIntHashMap;
import org.neo4j.collection.primitive.hopscotch.PrimitiveLongLongHashMap;
import org.neo4j.collection.primitive.hopscotch.PrimitiveLongObjectHashMap;
+import org.neo4j.memory.MemoryAllocationTracker;
import static org.neo4j.collection.primitive.hopscotch.HopScotchHashingAlgorithm.NO_MONITOR;
@@ -82,14 +83,14 @@ public static PrimitiveLongSet longSet( int initialCapacity )
VALUE_MARKER, NO_MONITOR );
}
- public static PrimitiveLongSet offHeapLongSet()
+ public static PrimitiveLongSet offHeapLongSet( MemoryAllocationTracker allocationTracker )
{
- return offHeapLongSet( DEFAULT_OFFHEAP_CAPACITY );
+ return offHeapLongSet( DEFAULT_OFFHEAP_CAPACITY, allocationTracker );
}
- public static PrimitiveLongSet offHeapLongSet( int initialCapacity )
+ public static PrimitiveLongSet offHeapLongSet( int initialCapacity, MemoryAllocationTracker allocationTracker )
{
- return new PrimitiveLongHashSet( new LongKeyUnsafeTable<>( initialCapacity, VALUE_MARKER ),
+ return new PrimitiveLongHashSet( new LongKeyUnsafeTable<>( initialCapacity, VALUE_MARKER, allocationTracker ),
VALUE_MARKER, NO_MONITOR );
}
@@ -113,14 +114,14 @@ public static PrimitiveLongLongMap longLongMap( int initialCapacity )
return new PrimitiveLongLongHashMap( new LongKeyLongValueTable( initialCapacity ), NO_MONITOR );
}
- public static PrimitiveLongLongMap offHeapLongLongMap()
+ public static PrimitiveLongLongMap offHeapLongLongMap( MemoryAllocationTracker allocationTracker )
{
- return offHeapLongLongMap( DEFAULT_OFFHEAP_CAPACITY );
+ return offHeapLongLongMap( DEFAULT_OFFHEAP_CAPACITY, allocationTracker );
}
- public static PrimitiveLongLongMap offHeapLongLongMap( int initialCapacity )
+ public static PrimitiveLongLongMap offHeapLongLongMap( int initialCapacity, MemoryAllocationTracker allocationTracker )
{
- return new PrimitiveLongLongHashMap( new LongKeyLongValueUnsafeTable( initialCapacity ), NO_MONITOR );
+ return new PrimitiveLongLongHashMap( new LongKeyLongValueUnsafeTable( initialCapacity, allocationTracker ), NO_MONITOR );
}
public static PrimitiveLongObjectMap longObjectMap()
@@ -144,15 +145,15 @@ public static PrimitiveIntSet intSet( int initialCapacity )
VALUE_MARKER, NO_MONITOR );
}
- public static PrimitiveIntSet offHeapIntSet()
+ public static PrimitiveIntSet offHeapIntSet( MemoryAllocationTracker allocationTracker )
{
- return new PrimitiveIntHashSet( new IntKeyUnsafeTable<>( 1 << 20, VALUE_MARKER ),
+ return new PrimitiveIntHashSet( new IntKeyUnsafeTable<>( 1 << 20, VALUE_MARKER, allocationTracker ),
VALUE_MARKER, NO_MONITOR );
}
- public static PrimitiveIntSet offHeapIntSet( int initialCapacity )
+ public static PrimitiveIntSet offHeapIntSet( int initialCapacity, MemoryAllocationTracker allocationTracker )
{
- return new PrimitiveIntHashSet( new IntKeyUnsafeTable<>( initialCapacity, VALUE_MARKER ),
+ return new PrimitiveIntHashSet( new IntKeyUnsafeTable<>( initialCapacity, VALUE_MARKER, allocationTracker ),
VALUE_MARKER, NO_MONITOR );
}
diff --git a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/IntKeyUnsafeTable.java b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/IntKeyUnsafeTable.java
index 7e5eb030fc899..3f2f51b0f12c2 100644
--- a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/IntKeyUnsafeTable.java
+++ b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/IntKeyUnsafeTable.java
@@ -19,13 +19,14 @@
*/
package org.neo4j.collection.primitive.hopscotch;
+import org.neo4j.memory.MemoryAllocationTracker;
import org.neo4j.unsafe.impl.internal.dragons.UnsafeUtil;
public class IntKeyUnsafeTable extends UnsafeTable
{
- public IntKeyUnsafeTable( int capacity, VALUE valueMarker )
+ public IntKeyUnsafeTable( int capacity, VALUE valueMarker, MemoryAllocationTracker allocationTracker )
{
- super( capacity, 4, valueMarker );
+ super( capacity, 4, valueMarker, allocationTracker );
}
@Override
@@ -46,6 +47,6 @@ protected void internalPut( long keyAddress, long key, VALUE value )
@Override
protected Table newInstance( int newCapacity )
{
- return new IntKeyUnsafeTable<>( newCapacity, valueMarker );
+ return new IntKeyUnsafeTable<>( newCapacity, valueMarker, allocationTracker );
}
}
diff --git a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyLongValueUnsafeTable.java b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyLongValueUnsafeTable.java
index 4173f7224b823..44e32c817e3e2 100644
--- a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyLongValueUnsafeTable.java
+++ b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyLongValueUnsafeTable.java
@@ -19,11 +19,13 @@
*/
package org.neo4j.collection.primitive.hopscotch;
+import org.neo4j.memory.MemoryAllocationTracker;
+
public class LongKeyLongValueUnsafeTable extends UnsafeTable
{
- public LongKeyLongValueUnsafeTable( int capacity )
+ public LongKeyLongValueUnsafeTable( int capacity, MemoryAllocationTracker allocationTracker )
{
- super( capacity, 16, new long[1] );
+ super( capacity, 16, new long[1], allocationTracker );
}
@Override
@@ -77,6 +79,6 @@ public long[] value( int index )
@Override
protected Table newInstance( int newCapacity )
{
- return new LongKeyLongValueUnsafeTable( newCapacity );
+ return new LongKeyLongValueUnsafeTable( newCapacity, allocationTracker );
}
}
diff --git a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyUnsafeTable.java b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyUnsafeTable.java
index a8e9fc8df4ba9..7de5cbb2f480f 100644
--- a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyUnsafeTable.java
+++ b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/LongKeyUnsafeTable.java
@@ -19,11 +19,13 @@
*/
package org.neo4j.collection.primitive.hopscotch;
+import org.neo4j.memory.MemoryAllocationTracker;
+
public class LongKeyUnsafeTable extends UnsafeTable
{
- public LongKeyUnsafeTable( int capacity, VALUE valueMarker )
+ public LongKeyUnsafeTable( int capacity, VALUE valueMarker, MemoryAllocationTracker allocationTracker )
{
- super( capacity, 8, valueMarker );
+ super( capacity, 8, valueMarker, allocationTracker );
}
@Override
@@ -41,6 +43,6 @@ protected void internalPut( long keyAddress, long key, VALUE value )
@Override
protected Table newInstance( int newCapacity )
{
- return new LongKeyUnsafeTable<>( newCapacity, valueMarker );
+ return new LongKeyUnsafeTable<>( newCapacity, valueMarker, allocationTracker );
}
}
diff --git a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/UnsafeTable.java b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/UnsafeTable.java
index 641ebd60bf7c2..24eceeff54574 100644
--- a/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/UnsafeTable.java
+++ b/community/primitive-collections/src/main/java/org/neo4j/collection/primitive/hopscotch/UnsafeTable.java
@@ -19,6 +19,7 @@
*/
package org.neo4j.collection.primitive.hopscotch;
+import org.neo4j.memory.MemoryAllocationTracker;
import org.neo4j.unsafe.impl.internal.dragons.UnsafeUtil;
public abstract class UnsafeTable extends PowerOfTwoQuantizedTable
@@ -26,16 +27,19 @@ public abstract class UnsafeTable extends PowerOfTwoQuantizedTable
private final int bytesPerKey;
private final int bytesPerEntry;
private final long dataSize;
+ private final long bytesToAllocate;
// address which should be free when closing
private final long allocatedAddress;
// address which should be used to access the table, the address where the table actually starts at
private final long address;
protected final VALUE valueMarker;
+ protected final MemoryAllocationTracker allocationTracker;
- protected UnsafeTable( int capacity, int bytesPerKey, VALUE valueMarker )
+ protected UnsafeTable( int capacity, int bytesPerKey, VALUE valueMarker, MemoryAllocationTracker allocationTracker )
{
super( capacity, 32 );
UnsafeUtil.assertHasUnsafe();
+ this.allocationTracker = allocationTracker;
this.bytesPerKey = bytesPerKey;
this.bytesPerEntry = 4 + bytesPerKey;
this.valueMarker = valueMarker;
@@ -54,7 +58,8 @@ protected UnsafeTable( int capacity, int bytesPerKey, VALUE valueMarker )
if ( UnsafeUtil.allowUnalignedMemoryAccess )
{
- this.allocatedAddress = this.address = UnsafeUtil.allocateMemory( dataSize );
+ bytesToAllocate = dataSize;
+ this.allocatedAddress = this.address = allocateMemory( bytesToAllocate );
}
else
{
@@ -69,7 +74,8 @@ protected UnsafeTable( int capacity, int bytesPerKey, VALUE valueMarker )
" yielding a bytesPerEntry:" + bytesPerEntry + ", which isn't 4-byte aligned." );
}
- this.allocatedAddress = UnsafeUtil.allocateMemory( dataSize + Integer.BYTES - 1 );
+ bytesToAllocate = dataSize + Integer.BYTES - 1;
+ this.allocatedAddress = allocateMemory( bytesToAllocate );
this.address = UnsafeUtil.alignedMemory( allocatedAddress, Integer.BYTES );
}
@@ -190,7 +196,7 @@ public void removeHopBit( int index, int hd )
@Override
public void close()
{
- UnsafeUtil.free( allocatedAddress );
+ deallocateMemory();
}
protected static void alignmentSafePutLongAsTwoInts( long address, long value )
@@ -219,4 +225,17 @@ protected static long alignmentSafeGetLongAsTwoInts( long address )
long msb = UnsafeUtil.getInt( address + Integer.BYTES ) & 0xFFFFFFFFL;
return lsb | (msb << Integer.SIZE);
}
+
+ private long allocateMemory( long bytesToAllocate )
+ {
+ long address = UnsafeUtil.allocateMemory( bytesToAllocate );
+ allocationTracker.allocate( bytesToAllocate );
+ return address;
+ }
+
+ private void deallocateMemory()
+ {
+ UnsafeUtil.free( allocatedAddress );
+ allocationTracker.deallocate( bytesToAllocate );
+ }
}
diff --git a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/PrimitiveIntCollectionsTest.java b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/PrimitiveIntCollectionsTest.java
index 7bb3541d784bc..5d29ff960e597 100644
--- a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/PrimitiveIntCollectionsTest.java
+++ b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/PrimitiveIntCollectionsTest.java
@@ -25,6 +25,8 @@
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
+import org.neo4j.memory.GlobalMemoryTracker;
+
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertArrayEquals;
@@ -54,7 +56,7 @@ public void arrayOfItemsAsIterator() throws Exception
public void convertCollectionToLongArray()
{
PrimitiveIntSet heapSet = PrimitiveIntCollections.asSet( new int[]{1, 2, 3} );
- PrimitiveIntSet offHeapIntSet = Primitive.offHeapIntSet();
+ PrimitiveIntSet offHeapIntSet = Primitive.offHeapIntSet( GlobalMemoryTracker.INSTANCE );
offHeapIntSet.add( 7 );
offHeapIntSet.add( 8 );
assertArrayEquals( new long[]{1, 2, 3}, PrimitiveIntCollections.asLongArray( heapSet ) );
diff --git a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/BasicTableTest.java b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/BasicTableTest.java
index 00dea23b32fa6..b4241f29a25e6 100644
--- a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/BasicTableTest.java
+++ b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/BasicTableTest.java
@@ -28,12 +28,11 @@
import java.util.Random;
import org.neo4j.collection.primitive.Primitive;
+import org.neo4j.memory.GlobalMemoryTracker;
+import static java.lang.System.currentTimeMillis;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-
-import static java.lang.System.currentTimeMillis;
-
import static org.neo4j.collection.primitive.Primitive.VALUE_MARKER;
@RunWith( Parameterized.class )
@@ -93,7 +92,7 @@ public Object sampleValue()
@Override
public Table newTable( int capacity )
{
- return new IntKeyUnsafeTable( capacity, VALUE_MARKER );
+ return new IntKeyUnsafeTable( capacity, VALUE_MARKER, GlobalMemoryTracker.INSTANCE );
}
@Override
@@ -113,7 +112,7 @@ public Object sampleValue()
@Override
public Table newTable( int capacity )
{
- return new LongKeyUnsafeTable( capacity, VALUE_MARKER );
+ return new LongKeyUnsafeTable( capacity, VALUE_MARKER, GlobalMemoryTracker.INSTANCE );
}
@Override
@@ -193,7 +192,7 @@ public Object sampleValue()
@Override
public Table newTable( int capacity )
{
- return new LongKeyLongValueUnsafeTable( capacity );
+ return new LongKeyLongValueUnsafeTable( capacity, GlobalMemoryTracker.INSTANCE );
}
@Override
diff --git a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveCollectionEqualityTest.java b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveCollectionEqualityTest.java
index 38ae732cf2552..1b76479b281fc 100644
--- a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveCollectionEqualityTest.java
+++ b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveCollectionEqualityTest.java
@@ -39,6 +39,7 @@
import org.neo4j.collection.primitive.PrimitiveLongObjectMap;
import org.neo4j.collection.primitive.PrimitiveLongSet;
import org.neo4j.function.Factory;
+import org.neo4j.memory.GlobalMemoryTracker;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@@ -272,10 +273,12 @@ public boolean remove( PrimitiveLongObjectMap coll )
public static Factory intSetWithCapacity = () -> Primitive.intSet( randomCapacity() );
@DataPoint
- public static Factory offheapIntSet = Primitive::offHeapIntSet;
+ public static Factory offheapIntSet =
+ () -> Primitive.offHeapIntSet( GlobalMemoryTracker.INSTANCE );
@DataPoint
- public static Factory offheapIntSetWithCapacity = () -> Primitive.offHeapIntSet( randomCapacity() );
+ public static Factory offheapIntSetWithCapacity =
+ () -> Primitive.offHeapIntSet( randomCapacity(), GlobalMemoryTracker.INSTANCE );
@DataPoint
public static Factory longSet = Primitive::longSet;
@@ -284,10 +287,12 @@ public boolean remove( PrimitiveLongObjectMap coll )
public static Factory longSetWithCapacity = () -> Primitive.longSet( randomCapacity() );
@DataPoint
- public static Factory offheapLongSet = Primitive::offHeapLongSet;
+ public static Factory offheapLongSet =
+ () -> Primitive.offHeapLongSet( GlobalMemoryTracker.INSTANCE );
@DataPoint
- public static Factory offheapLongSetWithCapacity = () -> Primitive.offHeapLongSet( randomCapacity() );
+ public static Factory offheapLongSetWithCapacity =
+ () -> Primitive.offHeapLongSet( randomCapacity(), GlobalMemoryTracker.INSTANCE );
@DataPoint
public static Factory intLongMap = Primitive::intLongMap;
@@ -309,11 +314,12 @@ public boolean remove( PrimitiveLongObjectMap coll )
() -> Primitive.longLongMap( randomCapacity() );
@DataPoint
- public static Factory offheapLongLongMap = Primitive::offHeapLongLongMap;
+ public static Factory offheapLongLongMap =
+ () -> Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE );
@DataPoint
public static Factory offheapLongLongMapWithCapacity =
- () -> Primitive.offHeapLongLongMap( randomCapacity() );
+ () -> Primitive.offHeapLongLongMap( randomCapacity(), GlobalMemoryTracker.INSTANCE );
@DataPoint
public static Factory intObjMap = Primitive::intObjectMap;
diff --git a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveLongMapTest.java b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveLongMapTest.java
index 9454381f71fa0..44e5b98e3746f 100644
--- a/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveLongMapTest.java
+++ b/community/primitive-collections/src/test/java/org/neo4j/collection/primitive/hopscotch/PrimitiveLongMapTest.java
@@ -42,6 +42,7 @@
import org.neo4j.collection.primitive.PrimitiveLongObjectMap;
import org.neo4j.collection.primitive.PrimitiveLongObjectVisitor;
import org.neo4j.collection.primitive.PrimitiveLongVisitor;
+import org.neo4j.memory.GlobalMemoryTracker;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
@@ -984,7 +985,7 @@ public void longLongOffHeapEntryVisitorShouldSeeAllEntriesIfItDoesNotBreakOut()
{
// GIVEN
PrimitiveLongLongVisitor visitor;
- try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap() )
+ try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE ) )
{
map.put( 1, 100 );
map.put( 2, 200 );
@@ -1007,7 +1008,7 @@ public void longLongOffHeapEntryVisitorShouldNotSeeEntriesAfterRequestingBreakOu
{
// GIVEN
AtomicInteger counter = new AtomicInteger();
- try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap() )
+ try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE ) )
{
map.put( 1, 100 );
map.put( 2, 200 );
@@ -1188,7 +1189,7 @@ public void longLongOffHeapKeyVisitorShouldSeeAllEntriesIfItDoesNotBreakOut()
{
// GIVEN
PrimitiveLongVisitor visitor = mock( PrimitiveLongVisitor.class );
- try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap() )
+ try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE ) )
{
map.put( 1, 100 );
map.put( 2, 200 );
@@ -1210,7 +1211,7 @@ public void longLongOffHeapKeyVisitorShouldNotSeeEntriesAfterRequestingBreakOut(
{
// GIVEN
AtomicInteger counter = new AtomicInteger();
- try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap() )
+ try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE ) )
{
map.put( 1, 100 );
map.put( 2, 200 );
@@ -1335,7 +1336,6 @@ public void recursivePutGrowInterleavingShouldNotDropOriginalValues()
@Test
public void recursivePutGrowInterleavingShouldNotDropOriginalValuesEvenWhenFirstGrowAddsMoreValuesAfterSecondGrow()
- throws Exception
{
// List of values that cause recursive growth like above, but this time the first grow wants to add more values
// to the table *after* the second grow has occurred.
diff --git a/tools/src/main/java/org/neo4j/tools/txlog/CheckTxLogs.java b/tools/src/main/java/org/neo4j/tools/txlog/CheckTxLogs.java
index b052c1d7cee79..5608f8aa5d0bb 100644
--- a/tools/src/main/java/org/neo4j/tools/txlog/CheckTxLogs.java
+++ b/tools/src/main/java/org/neo4j/tools/txlog/CheckTxLogs.java
@@ -43,6 +43,7 @@
import org.neo4j.kernel.impl.transaction.log.entry.LogEntryCommit;
import org.neo4j.kernel.impl.transaction.log.files.LogFiles;
import org.neo4j.kernel.impl.transaction.log.files.LogFilesBuilder;
+import org.neo4j.memory.GlobalMemoryTracker;
import org.neo4j.storageengine.api.StorageCommand;
import org.neo4j.tools.txlog.checktypes.CheckType;
import org.neo4j.tools.txlog.checktypes.CheckTypes;
@@ -127,7 +128,7 @@ boolean validateCheckPoints( LogFiles logFiles, InconsistenciesHandler handler )
final long lowestLogVersion = logFiles.getLowestLogVersion();
final long highestLogVersion = logFiles.getHighestLogVersion();
boolean success = true;
- try ( PrimitiveLongLongMap logFileSizes = Primitive.offHeapLongLongMap() )
+ try ( PrimitiveLongLongMap logFileSizes = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE ) )
{
for ( long i = lowestLogVersion; i <= highestLogVersion; i++ )
{