Skip to content

Commit 7712f67

Browse files
authored
Merge pull request #61 from GReD-Clermont/fix-import-multithreaded
Fix import in multithreaded context
2 parents b3021a8 + 07eae6c commit 7712f67

7 files changed

Lines changed: 114 additions & 15 deletions

File tree

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
<parent>
55
<artifactId>pom-scijava</artifactId>
66
<groupId>org.scijava</groupId>
7-
<version>34.1.0</version>
7+
<version>35.1.1</version>
88
</parent>
99

1010
<groupId>fr.igred</groupId>
1111
<artifactId>simple-omero-client</artifactId>
12-
<version>5.12.3</version>
12+
<version>5.13.0</version>
1313
<packaging>jar</packaging>
1414

1515
<name>Simple OMERO Client</name>

src/main/java/fr/igred/omero/GatewayWrapper.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import ome.formats.OMEROMetadataStoreClient;
2727
import omero.api.IQueryPrx;
2828
import omero.gateway.Gateway;
29-
import omero.gateway.JoinSessionCredentials;
3029
import omero.gateway.LoginCredentials;
3130
import omero.gateway.SecurityContext;
3231
import omero.gateway.exception.DSOutOfServiceException;
@@ -43,6 +42,9 @@
4342

4443
import java.util.List;
4544
import java.util.concurrent.ExecutionException;
45+
import java.util.concurrent.atomic.AtomicInteger;
46+
import java.util.concurrent.locks.Lock;
47+
import java.util.concurrent.locks.ReentrantLock;
4648

4749

4850
/**
@@ -52,6 +54,12 @@
5254
*/
5355
public abstract class GatewayWrapper {
5456

57+
/** Number of requested import stores */
58+
private final AtomicInteger storeUses = new AtomicInteger(0);
59+
60+
/** Import store lock */
61+
private final Lock storeLock = new ReentrantLock(true);
62+
5563
/** Gateway linking the code to OMERO, only linked to one group. */
5664
private Gateway gateway;
5765

@@ -87,6 +95,35 @@ public Gateway getGateway() {
8795
}
8896

8997

98+
/**
99+
* Retrieves the shared import store in a thread-safe way.
100+
*
101+
* @throws DSOutOfServiceException If the connection is broken, or not logged in.
102+
*/
103+
private OMEROMetadataStoreClient getImportStoreLocked() throws DSOutOfServiceException {
104+
storeLock.lock();
105+
try {
106+
return gateway.getImportStore(ctx);
107+
} finally {
108+
storeLock.unlock();
109+
}
110+
}
111+
112+
113+
/**
114+
* Closes the import store in a thread-safe manner.
115+
*/
116+
private void closeImportStoreLocked() {
117+
if (storeLock.tryLock()) {
118+
try {
119+
gateway.closeImport(ctx, null);
120+
} finally {
121+
storeLock.unlock();
122+
}
123+
}
124+
}
125+
126+
90127
/**
91128
* Returns the current user.
92129
*
@@ -163,7 +200,7 @@ public boolean isConnected() {
163200
*/
164201
public void connect(String hostname, int port, String sessionId)
165202
throws ServiceException {
166-
connect(new JoinSessionCredentials(sessionId, hostname, port));
203+
connect(new LoginCredentials(sessionId, sessionId, hostname, port));
167204
}
168205

169206

@@ -233,6 +270,8 @@ public void connect(LoginCredentials cred) throws ServiceException {
233270
public void disconnect() {
234271
if (isConnected()) {
235272
boolean sudo = ctx.isSudo();
273+
storeUses.set(0);
274+
closeImport();
236275
user = new ExperimenterWrapper(new ExperimenterData());
237276
ctx = new SecurityContext(-1);
238277
ctx.setExperimenter(user.asDataObject());
@@ -348,18 +387,30 @@ public AdminFacility getAdminFacility() throws ExecutionException {
348387
/**
349388
* Creates or recycles the import store.
350389
*
351-
* @return config.
390+
* @return See above.
352391
*
353392
* @throws ServiceException Cannot connect to OMERO.
354393
*/
355394
public OMEROMetadataStoreClient getImportStore() throws ServiceException {
356-
return ExceptionHandler.of(gateway, g -> g.getImportStore(ctx))
395+
storeUses.incrementAndGet();
396+
return ExceptionHandler.of(this, GatewayWrapper::getImportStoreLocked)
357397
.rethrow(DSOutOfServiceException.class, ServiceException::new,
358398
"Could not retrieve import store")
359399
.get();
360400
}
361401

362402

403+
/**
404+
* Closes the import store.
405+
*/
406+
public void closeImport() {
407+
int remainingStores = storeUses.decrementAndGet();
408+
if (remainingStores <= 0) {
409+
closeImportStoreLocked();
410+
}
411+
}
412+
413+
363414
/**
364415
* Finds objects on OMERO through a database query.
365416
*

src/main/java/fr/igred/omero/repository/DatasetWrapper.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,28 @@ public void removeImage(Client client, ImageWrapper image)
463463
*/
464464
public boolean importImages(Client client, String... paths)
465465
throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException {
466-
boolean success = importImages(client, data, paths);
466+
return importImages(client, 1, paths);
467+
}
468+
469+
470+
/**
471+
* Imports all images candidates in the paths to the dataset in OMERO.
472+
*
473+
* @param client The client handling the connection.
474+
* @param threads The number of threads (same value used for filesets and uploads).
475+
* @param paths Paths to the image files on the computer.
476+
*
477+
* @return If the import did not exit because of an error.
478+
*
479+
* @throws ServiceException Cannot connect to OMERO.
480+
* @throws AccessException Cannot access data.
481+
* @throws OMEROServerError Server error.
482+
* @throws IOException Cannot read file.
483+
* @throws ExecutionException A Facility can't be retrieved or instantiated.
484+
*/
485+
public boolean importImages(Client client, int threads, String... paths)
486+
throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException {
487+
boolean success = importImages(client, data, threads, paths);
467488
refresh(client);
468489
return success;
469490
}

src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,18 @@ protected GenericRepositoryObjectWrapper(T o) {
7070
/**
7171
* Imports all images candidates in the paths to the target in OMERO.
7272
*
73-
* @param client The client handling the connection.
74-
* @param target The import target.
75-
* @param paths Paths to the image files on the computer.
73+
* @param client The client handling the connection.
74+
* @param target The import target.
75+
* @param threads The number of threads (same value used for filesets and uploads).
76+
* @param paths Paths to the image files on the computer.
7677
*
7778
* @return If the import did not exit because of an error.
7879
*
7980
* @throws ServiceException Cannot connect to OMERO.
8081
* @throws OMEROServerError Server error.
8182
* @throws IOException Cannot read file.
8283
*/
83-
protected static boolean importImages(GatewayWrapper client, DataObject target, String... paths)
84+
protected static boolean importImages(GatewayWrapper client, DataObject target, int threads, String... paths)
8485
throws ServiceException, OMEROServerError, IOException {
8586
boolean success;
8687

@@ -89,6 +90,8 @@ protected static boolean importImages(GatewayWrapper client, DataObject target,
8990
config.target.set(type + ":" + target.getId());
9091
config.username.set(client.getUser().getUserName());
9192
config.email.set(client.getUser().getEmail());
93+
config.parallelFileset.set(threads);
94+
config.parallelUpload.set(threads);
9295

9396
OMEROMetadataStoreClient store = client.getImportStore();
9497
try (OMEROWrapper reader = new OMEROWrapper(config)) {
@@ -107,7 +110,7 @@ protected static boolean importImages(GatewayWrapper client, DataObject target,
107110
ImportCandidates candidates = new ImportCandidates(reader, paths, handler);
108111
success = library.importCandidates(config, candidates);
109112
} finally {
110-
store.logout();
113+
client.closeImport();
111114
}
112115

113116
return success;
@@ -163,7 +166,7 @@ protected static List<Long> importImage(GatewayWrapper client, DataObject target
163166
} catch (Throwable e) {
164167
throw new OMEROServerError(e);
165168
} finally {
166-
store.logout();
169+
client.closeImport();
167170
}
168171

169172
List<Long> ids = new ArrayList<>(pixels.size());

src/main/java/fr/igred/omero/repository/ScreenWrapper.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,28 @@ public void refresh(GatewayWrapper client) throws ServiceException, AccessExcept
351351
*/
352352
public boolean importImages(GatewayWrapper client, String... paths)
353353
throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException {
354-
boolean success = importImages(client, data, paths);
354+
return this.importImages(client, 1, paths);
355+
}
356+
357+
358+
/**
359+
* Imports all images candidates in the paths to the screen in OMERO.
360+
*
361+
* @param client The client handling the connection.
362+
* @param threads The number of threads (same value used for filesets and uploads).
363+
* @param paths Paths to the image files on the computer.
364+
*
365+
* @return If the import did not exit because of an error.
366+
*
367+
* @throws ServiceException Cannot connect to OMERO.
368+
* @throws AccessException Cannot access data.
369+
* @throws OMEROServerError Server error.
370+
* @throws IOException Cannot read file.
371+
* @throws ExecutionException A Facility can't be retrieved or instantiated.
372+
*/
373+
public boolean importImages(GatewayWrapper client, int threads, String... paths)
374+
throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException {
375+
boolean success = importImages(client, data, threads, paths);
355376
refresh(client);
356377
return success;
357378
}

src/test/java/fr/igred/omero/SudoTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ void sudoImport() throws Exception {
109109

110110
List<ImageWrapper> images = dataset.getImages(client3);
111111
assertEquals(1, images.size());
112+
assertEquals(client3.getId(), images.get(0).getOwner().getId());
113+
assertEquals(6L, images.get(0).getGroupId());
112114

113115
client4.delete(images.get(0));
114116
client4.delete(dataset);

src/test/java/fr/igred/omero/repository/ImageImportTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ void testImportImage() throws Exception {
4949

5050
DatasetWrapper dataset = client.getDataset(DATASET2.id);
5151

52-
boolean imported = dataset.importImages(client, f1.getAbsolutePath(), f2.getAbsolutePath());
52+
boolean imported = dataset.importImages(client, 2, f1.getAbsolutePath(), f2.getAbsolutePath());
53+
client.closeImport();
5354

5455
removeFile(f1);
5556
removeFile(f2);

0 commit comments

Comments
 (0)