Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0c636f1

Browse files
committed
Hold strong reference to all buffers passed to LmdbJava (fixeslmdbjava#207)
1 parent9cf97a5 commit0c636f1

File tree

5 files changed

+187
-0
lines changed

5 files changed

+187
-0
lines changed

‎pom.xml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@
8888
<version>0.9.29-1</version>
8989
<optional>true</optional>
9090
</dependency>
91+
<dependency>
92+
<groupId>org.mockito</groupId>
93+
<artifactId>mockito-inline</artifactId>
94+
<version>4.11.0</version>
95+
<scope>test</scope>
96+
</dependency>
9197
</dependencies>
9298
<build>
9399
<plugins>
@@ -110,6 +116,8 @@
110116
</usedDependencies>
111117
<ignoredDependencies>
112118
<ignoredDependency>com.github.jnr:jffi</ignoredDependency>
119+
<ignoredDependency>org.mockito:mockito-core</ignoredDependency>
120+
<ignoredDependency>org.mockito:mockito-inline</ignoredDependency>
113121
</ignoredDependencies>
114122
</configuration>
115123
</plugin>

‎src/main/java/org/lmdbjava/Cursor.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public boolean get(final T key, final T data, final SeekOp op) {
162162
checkRc(rc);
163163
kv.keyOut();
164164
kv.valOut();
165+
ReferenceUtil.reachabilityFence0(key);
165166
returntrue;
166167
}
167168

@@ -192,6 +193,7 @@ public boolean get(final T key, final GetOp op) {
192193
checkRc(rc);
193194
kv.keyOut();
194195
kv.valOut();
196+
ReferenceUtil.reachabilityFence0(key);
195197
returntrue;
196198
}
197199

@@ -266,6 +268,8 @@ public boolean put(final T key, final T val, final PutFlags... op) {
266268
returnfalse;
267269
}
268270
checkRc(rc);
271+
ReferenceUtil.reachabilityFence0(key);
272+
ReferenceUtil.reachabilityFence0(val);
269273
returntrue;
270274
}
271275

@@ -304,6 +308,8 @@ public void putMultiple(final T key, final T val, final int elements,
304308
finalintrc =LIB.mdb_cursor_put(ptrCursor,txn.kv().pointerKey(),
305309
dataPtr,mask);
306310
checkRc(rc);
311+
ReferenceUtil.reachabilityFence0(key);
312+
ReferenceUtil.reachabilityFence0(val);
307313
}
308314

309315
/**
@@ -362,6 +368,7 @@ public T reserve(final T key, final int size, final PutFlags... op) {
362368
checkRc(LIB.mdb_cursor_put(ptrCursor,kv.pointerKey(),kv.pointerVal(),
363369
flags));
364370
kv.valOut();
371+
ReferenceUtil.reachabilityFence0(key);
365372
returnval();
366373
}
367374

‎src/main/java/org/lmdbjava/Dbi.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ public boolean delete(final Txn<T> txn, final T key, final T val) {
171171
returnfalse;
172172
}
173173
checkRc(rc);
174+
ReferenceUtil.reachabilityFence0(key);
175+
ReferenceUtil.reachabilityFence0(val);
174176
returntrue;
175177
}
176178

@@ -239,6 +241,7 @@ public T get(final Txn<T> txn, final T key) {
239241
returnnull;
240242
}
241243
checkRc(rc);
244+
ReferenceUtil.reachabilityFence0(key);
242245
returntxn.kv().valOut();// marked as out in LMDB C docs
243246
}
244247

@@ -386,6 +389,8 @@ public boolean put(final Txn<T> txn, final T key, final T val,
386389
returnfalse;
387390
}
388391
checkRc(rc);
392+
ReferenceUtil.reachabilityFence0(key);
393+
ReferenceUtil.reachabilityFence0(val);
389394
returntrue;
390395
}
391396

@@ -421,6 +426,7 @@ public T reserve(final Txn<T> txn, final T key, final int size,
421426
checkRc(LIB.mdb_put(txn.pointer(),ptr,txn.kv().pointerKey(),txn.kv()
422427
.pointerVal(),flags));
423428
txn.kv().valOut();// marked as in,out in LMDB C docs
429+
ReferenceUtil.reachabilityFence0(key);
424430
returntxn.val();
425431
}
426432

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*-
2+
* #%L
3+
* LmdbJava
4+
* %%
5+
* Copyright (C) 2016 - 2023 The LmdbJava Open Source Project
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
21+
packageorg.lmdbjava;
22+
23+
importedu.umd.cs.findbugs.annotations.SuppressFBWarnings;
24+
25+
publicfinalclassReferenceUtil {
26+
/**
27+
* Ensures that the object referenced by the given reference remains
28+
* <a href="package-summary.html#reachability"><em>strongly reachable</em></a>,
29+
* regardless of any prior actions of the program that might otherwise cause
30+
* the object to become unreachable; thus, the referenced object is not
31+
* reclaimable by garbage collection at least until after the invocation of
32+
* this method.
33+
*
34+
* <p> Recent versions of the JDK have a nasty habit of prematurely deciding objects are unreachable.
35+
* see: https://stackoverflow.com/questions/26642153/finalize-called-on-strongly-reachable-object-in-java-8
36+
* The Java 9 method Reference.reachabilityFence offers a solution to this problem.
37+
*
38+
* <p> This method is always implemented as a synchronization on {@code ref}, not as
39+
* {@code Reference.reachabilityFence} for consistency across platforms and to allow building on JDK 6-8.
40+
* <b>It is the caller's responsibility to ensure that this synchronization will not cause deadlock.</b>
41+
*
42+
* @param ref the reference. If {@code null}, this method has no effect.
43+
* @see https://github.com/netty/netty/pull/8410
44+
*/
45+
@SuppressFBWarnings({"ESync_EMPTY_SYNC","UC_USELESS_VOID_METHOD"})
46+
publicstaticvoidreachabilityFence0(Objectref) {
47+
if (ref !=null) {
48+
synchronized (ref) {
49+
// Empty synchronized is ok: https://stackoverflow.com/a/31933260/1151521
50+
}
51+
}
52+
}
53+
54+
privateReferenceUtil() {}
55+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*-
2+
* #%L
3+
* LmdbJava
4+
* %%
5+
* Copyright (C) 2016 - 2023 The LmdbJava Open Source Project
6+
* %%
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* #L%
19+
*/
20+
21+
packageorg.lmdbjava;
22+
23+
importedu.umd.cs.findbugs.annotations.SuppressFBWarnings;
24+
importorg.junit.Rule;
25+
importorg.junit.Test;
26+
importorg.junit.rules.TemporaryFolder;
27+
importorg.mockito.MockedStatic;
28+
importorg.mockito.Mockito;
29+
30+
importjava.io.File;
31+
importjava.io.IOException;
32+
importjava.nio.ByteBuffer;
33+
34+
importstaticjava.nio.ByteBuffer.allocateDirect;
35+
importstaticjava.nio.charset.StandardCharsets.UTF_8;
36+
importstaticorg.junit.Assert.fail;
37+
importstaticorg.lmdbjava.DbiFlags.MDB_CREATE;
38+
importstaticorg.lmdbjava.Env.create;
39+
40+
@SuppressFBWarnings({"DM_GC","RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT"})
41+
@SuppressWarnings("PMD.DoNotCallGarbageCollectionExplicitly")
42+
publicclassGarbageCollectionTest {
43+
44+
privatestaticfinalStringDB_NAME ="my DB";
45+
privatestaticfinalStringKEY_PREFIX ="Uncorruptedkey";
46+
privatestaticfinalStringVAL_PREFIX ="Uncorruptedval";
47+
48+
@Rule
49+
publicfinalTemporaryFoldertmp =newTemporaryFolder();
50+
privatevoidputBuffer(Dbi<ByteBuffer>db,Txn<ByteBuffer>txn,inti) {
51+
ByteBufferkey =allocateDirect(24);
52+
ByteBufferval =allocateDirect(24);
53+
key.put((KEY_PREFIX+i).getBytes(UTF_8)).flip();
54+
val.put((VAL_PREFIX+i).getBytes(UTF_8)).flip();
55+
db.put(txn,key,val);
56+
}
57+
@Test
58+
publicvoidbuffersNotGarbageCollectedTest()throwsIOException {
59+
finalFilepath =tmp.newFolder();
60+
61+
finalEnv<ByteBuffer>env =create()
62+
.setMapSize(2_085_760_999)
63+
.setMaxDbs(1)
64+
.open(path);
65+
finalDbi<ByteBuffer>db =env.openDbi(DB_NAME,MDB_CREATE);
66+
67+
// Trigger compilation and whatnot
68+
try (Txn<ByteBuffer>txn =env.txnWrite()) {
69+
for (inti =0;i <5000;i++) {
70+
putBuffer(db,txn,i);
71+
}
72+
txn.commit();
73+
}
74+
// Call gc before writing to lmdb and after last reference to buffer by changing the behavior of mask
75+
try (MockedStatic<MaskedFlag>mockedStatic =Mockito.mockStatic(MaskedFlag.class)) {
76+
mockedStatic.when(MaskedFlag::mask).thenAnswer(invocationOnMock -> {
77+
System.gc();
78+
return0;
79+
});
80+
try (Txn<ByteBuffer>txn =env.txnWrite()) {
81+
for (inti =0;i <1000;i++) {
82+
putBuffer(db,txn,i);
83+
}
84+
txn.commit();
85+
}
86+
}
87+
88+
// Find corrupt keys
89+
try (Txn<ByteBuffer>txn =env.txnRead()) {
90+
try (Cursor<ByteBuffer>c =db.openCursor(txn)) {
91+
if (c.first()) {
92+
do {
93+
byte[]rkey =newbyte[c.key().remaining()];
94+
c.key().get(rkey);
95+
byte[]rval =newbyte[c.val().remaining()];
96+
c.val().get(rval);
97+
Stringskey =newString(rkey,UTF_8);
98+
Stringsval =newString(rval,UTF_8);
99+
if (!skey.startsWith("Uncorruptedkey")) {
100+
fail("Found corrupt key " +skey);
101+
}
102+
if (!sval.startsWith("Uncorruptedval")) {
103+
fail("Found corrupt val " +sval);
104+
}
105+
}while (c.next());
106+
}
107+
}
108+
}
109+
env.close();
110+
}
111+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp