Skip to content

Commit 12ba0c3

Browse files
committed
Support OpenSlide cache management API
Use the same semantics as the OpenSlide API. The OpenSlide class implements java.io.Closeable, which is documented to be for "a source or destination of data that can be closed". OpenSlideCache is technically a source or destination of data, but not at the Java API level, and the only reason it needs to be closeable is to release the underlying resource in the C API. Its superinterface java.lang.AutoCloseable is documented to be for "an object that may hold resources [...] until it is closed"; implement that instead. OpenSlide has a legacy dispose() method which is an alias for close(). Don't add a similar method to OpenSlideCache. Closes: #36 Signed-off-by: Benjamin Gilbert <[email protected]>
1 parent dabbd6b commit 12ba0c3

File tree

5 files changed

+124
-3
lines changed

5 files changed

+124
-3
lines changed

org/openslide/OpenSlide.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* OpenSlide, a library for reading whole slide image files
33
*
44
* Copyright (c) 2007-2011 Carnegie Mellon University
5+
* Copyright (c) 2024 Benjamin Gilbert
56
* All rights reserved.
67
*
78
* OpenSlide is free software: you can redistribute it and/or modify
@@ -420,6 +421,20 @@ BufferedImage getAssociatedImage(String name) throws IOException {
420421
}
421422
}
422423

424+
public void setCache(OpenSlideCache cache) {
425+
Lock cl = cache.getLock();
426+
Lock rl = lock.readLock();
427+
cl.lock();
428+
rl.lock();
429+
try {
430+
checkDisposed();
431+
OpenSlideFFM.openslide_set_cache(osr, cache.getSegment());
432+
} finally {
433+
rl.unlock();
434+
cl.unlock();
435+
}
436+
}
437+
423438
public static String getLibraryVersion() {
424439
return LIBRARY_VERSION;
425440
}

org/openslide/OpenSlideCache.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* OpenSlide, a library for reading whole slide image files
3+
*
4+
* Copyright (c) 2007-2011 Carnegie Mellon University
5+
* Copyright (c) 2024 Benjamin Gilbert
6+
* All rights reserved.
7+
*
8+
* OpenSlide is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as
10+
* published by the Free Software Foundation, version 2.1.
11+
*
12+
* OpenSlide is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with OpenSlide. If not, see
19+
* <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
package org.openslide;
24+
25+
import java.lang.foreign.MemorySegment;
26+
import java.util.concurrent.locks.Lock;
27+
import java.util.concurrent.locks.ReentrantLock;
28+
29+
public final class OpenSlideCache implements AutoCloseable {
30+
private final Lock lock = new ReentrantLock();
31+
32+
private MemorySegment cache;
33+
34+
public OpenSlideCache(long capacity) {
35+
cache = OpenSlideFFM.openslide_cache_create(capacity);
36+
}
37+
38+
Lock getLock() {
39+
return lock;
40+
}
41+
42+
// call, and use result, with lock held
43+
MemorySegment getSegment() {
44+
if (cache == null) {
45+
throw new OpenSlideDisposedException("OpenSlideCache");
46+
}
47+
return cache;
48+
}
49+
50+
// takes the lock
51+
@Override
52+
public void close() {
53+
lock.lock();
54+
try {
55+
if (cache != null) {
56+
OpenSlideFFM.openslide_cache_release(cache);
57+
cache = null;
58+
}
59+
} finally {
60+
lock.unlock();
61+
}
62+
}
63+
}

org/openslide/OpenSlideDisposedException.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
package org.openslide;
2323

2424
public class OpenSlideDisposedException extends RuntimeException {
25-
private static final String MSG = "OpenSlide object has been disposed";
25+
private static final String MSG = " object has been closed";
2626

2727
public OpenSlideDisposedException() {
28-
super(MSG);
28+
this("OpenSlide");
29+
}
30+
31+
public OpenSlideDisposedException(String what) {
32+
super(what + MSG);
2933
}
3034
}

org/openslide/OpenSlideFFM.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class OpenSlideFFM {
3434
private static final AddressLayout C_POINTER = ADDRESS.withTargetLayout(
3535
MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_BYTE));
3636

37+
private static final MemoryLayout SIZE_T = Linker.nativeLinker()
38+
.canonicalLayouts().get("size_t");
39+
3740
private OpenSlideFFM() {
3841
}
3942

@@ -305,6 +308,39 @@ static void openslide_read_associated_image(MemorySegment osr, String name,
305308
}
306309
}
307310

311+
private static final MethodHandle cache_create = function(
312+
C_POINTER, "openslide_cache_create", SIZE_T);
313+
314+
static MemorySegment openslide_cache_create(long capacity) {
315+
try {
316+
return (MemorySegment) cache_create.invokeExact(capacity);
317+
} catch (Throwable ex) {
318+
throw new AssertionError("Invalid call", ex);
319+
}
320+
}
321+
322+
private static final MethodHandle set_cache = function(
323+
null, "openslide_set_cache", C_POINTER, C_POINTER);
324+
325+
static void openslide_set_cache(MemorySegment osr, MemorySegment cache) {
326+
try {
327+
set_cache.invokeExact(osr, cache);
328+
} catch (Throwable ex) {
329+
throw new AssertionError("Invalid call", ex);
330+
}
331+
}
332+
333+
private static final MethodHandle cache_release = function(
334+
null, "openslide_cache_release", C_POINTER);
335+
336+
static void openslide_cache_release(MemorySegment cache) {
337+
try {
338+
cache_release.invokeExact(cache);
339+
} catch (Throwable ex) {
340+
throw new AssertionError("Invalid call", ex);
341+
}
342+
}
343+
308344
private static final MethodHandle get_version = function(
309345
C_POINTER, "openslide_get_version");
310346

org/openslide/TestCLI.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ public static void main(String args[]) throws IOException {
5656

5757
osr.dispose();
5858

59-
osr = new OpenSlide(f);
59+
try (OpenSlideCache cache = new OpenSlideCache(64 << 20)) {
60+
osr = new OpenSlide(f);
61+
osr.setCache(cache);
62+
}
6063

6164
w = osr.getLevel0Width();
6265
h = osr.getLevel0Height();

0 commit comments

Comments
 (0)