From 01f15fb9b124531a31864553178cba03c50afa1c Mon Sep 17 00:00:00 2001 From: leventov Date: Fri, 5 Feb 2016 16:35:46 +0700 Subject: [PATCH] Fix msync JNA implementations and add SimplePersistedMapOverflowTest --- .../hash/impl/VanillaChronicleHash.java | 12 ++++-- .../hash/impl/{ => util/jna}/PosixMsync.java | 28 ++++++++++---- .../impl/{ => util/jna}/WindowsMsync.java | 23 +++++++----- .../map/SimplePersistedMapOverflowTest.java | 37 +++++++++++++++++++ 4 files changed, 79 insertions(+), 21 deletions(-) rename src/main/java/net/openhft/chronicle/hash/impl/{ => util/jna}/PosixMsync.java (59%) rename src/main/java/net/openhft/chronicle/hash/impl/{ => util/jna}/WindowsMsync.java (71%) create mode 100644 src/test/java/net/openhft/chronicle/map/SimplePersistedMapOverflowTest.java diff --git a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java index 65d47a13c..255529653 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java @@ -24,6 +24,8 @@ import net.openhft.chronicle.core.Maths; import net.openhft.chronicle.core.OS; import net.openhft.chronicle.hash.*; import net.openhft.chronicle.hash.impl.util.BuildVersion; +import net.openhft.chronicle.hash.impl.util.jna.PosixMsync; +import net.openhft.chronicle.hash.impl.util.jna.WindowsMsync; import net.openhft.chronicle.hash.serialization.DataAccess; import net.openhft.chronicle.hash.serialization.SizeMarshaller; import net.openhft.chronicle.hash.serialization.SizedReader; @@ -762,10 +764,6 @@ public abstract class VanillaChronicleHash. */ -package net.openhft.chronicle.hash.impl; +package net.openhft.chronicle.hash.impl.util.jna; +import com.sun.jna.IntegerType; import com.sun.jna.Native; import com.sun.jna.Platform; +import com.sun.jna.Pointer; import java.io.IOException; -final class PosixMsync { +public final class PosixMsync { private static final int MS_SYNC = 4; public static void msync(long addr, long length) throws IOException { - if (msync(addr, length, MS_SYNC) == -1) - throw new IOException(strerror_r(Native.getLastError(), null, 0)); + if (msync(new Pointer(addr), new size_t(length), MS_SYNC) == -1) + throw new IOException("msync failed: error code " + Native.getLastError()); } - private static native String strerror_r(int errnum, char[] buf, int buflen); - - private static native int msync(long addr, long length, int flags); + private static native int msync(Pointer addr, size_t length, int flags); static { Native.register(PosixMsync.class, Platform.C_LIBRARY_NAME); } private PosixMsync() {} + + public static class size_t extends IntegerType { + private static final long serialVersionUID = 0L; + + // no-arg constructor is required by JNA + @SuppressWarnings("unused") + public size_t() { + this(0); + } + + public size_t(long value) { + super(Native.SIZE_T_SIZE, value, true); + } + } } diff --git a/src/main/java/net/openhft/chronicle/hash/impl/WindowsMsync.java b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java similarity index 71% rename from src/main/java/net/openhft/chronicle/hash/impl/WindowsMsync.java rename to src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java index b5f97d873..ce5043119 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/WindowsMsync.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/util/jna/WindowsMsync.java @@ -14,17 +14,21 @@ * along with this program. If not, see . */ -package net.openhft.chronicle.hash.impl; +package net.openhft.chronicle.hash.impl.util.jna; import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.BaseTSD.SIZE_T; +import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.Kernel32Util; +import com.sun.jna.win32.W32APIOptions; import java.io.IOException; import java.io.RandomAccessFile; import static com.sun.jna.platform.win32.WinError.ERROR_LOCK_VIOLATION; -final class WindowsMsync { +public final class WindowsMsync { public static void msync(RandomAccessFile raf, long addr, long length) throws IOException { @@ -35,8 +39,8 @@ final class WindowsMsync { // pages to disk. As there is no way to synchronize the flushing then we retry a limited // number of times. do { - if ((success = FlushViewOfFile(addr, length)) || - (lastError = GetLastError()) != ERROR_LOCK_VIOLATION) + success = KERNEL_32.FlushViewOfFile(new Pointer(addr), new SIZE_T(length)); + if (success || (lastError = KERNEL_32.GetLastError()) != ERROR_LOCK_VIOLATION) break; retry++; } while (retry < 3); @@ -49,13 +53,12 @@ final class WindowsMsync { } } - private static native boolean FlushViewOfFile(long addr, long length); - - private static native int GetLastError(); - - static { - Native.register(WindowsMsync.class, "kernel32"); + public interface Kernel32Ex extends Kernel32 { + boolean FlushViewOfFile(Pointer addr, SIZE_T length); } + private static final Kernel32Ex KERNEL_32 = (Kernel32Ex) + Native.loadLibrary("kernel32", Kernel32Ex.class, W32APIOptions.UNICODE_OPTIONS); + private WindowsMsync() {} } diff --git a/src/test/java/net/openhft/chronicle/map/SimplePersistedMapOverflowTest.java b/src/test/java/net/openhft/chronicle/map/SimplePersistedMapOverflowTest.java new file mode 100644 index 000000000..31c74b519 --- /dev/null +++ b/src/test/java/net/openhft/chronicle/map/SimplePersistedMapOverflowTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 higherfrequencytrading.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package net.openhft.chronicle.map; + +import net.openhft.chronicle.set.Builder; +import org.junit.Test; + +import java.io.IOException; + +public class SimplePersistedMapOverflowTest { + + @Test + public void simplePersistedMapOverflowTest() throws IOException { + try (ChronicleMap map = ChronicleMap + .of(Integer.class, Integer.class) + .entries(1_000) + .createPersistedTo(Builder.getPersistenceFile())) { + for (int i = 0; i < 2_000; i++) { + map.put(i, i); + } + } + } +}