Currently, the FileSystemKeyValueAccess implementation relies on locking files for read/write by using the built in FileLock mechanism. This lock is always exclusive for writing, but can be shared for read attempts. The issues is that this functionality is not provided by the JVM. What the JVM facilitates with shared FileLocks is to allow other processes to also get a shared FileLock. However, if you try to get a shared FileLock that is already held by another thread, the lock method will be blocking. This results in all read attempts on the same file to be effectively single-threaded.
This is particularly noticeable when using methods that constantly query the dataset-attributes per-block, which can cause each thread to block on the getAttributes method. It is also noticeable when creating many readers/writers at the same location, as the lock get block on getVersion during construction.
Ensuring the the N5Reader/Writer is using a gson cache solves this in part, but the underlying problem still persists. In large parallel environments, where it is difficult to re-use the N5Reader/Writer instance across threads (e.g. when using Spark) this can be particularly harmful, and either require explicit logic to share the cache across threads on the same JVM, or result in effectively single-thread read performance.
A solution would be to implement proper ReadWriteLock access.
Currently, the FileSystemKeyValueAccess implementation relies on locking files for read/write by using the built in FileLock mechanism. This lock is always exclusive for writing, but can be shared for read attempts. The issues is that this functionality is not provided by the JVM. What the JVM facilitates with shared FileLocks is to allow other processes to also get a shared FileLock. However, if you try to get a shared FileLock that is already held by another thread, the
lockmethod will be blocking. This results in all read attempts on the same file to be effectively single-threaded.This is particularly noticeable when using methods that constantly query the dataset-attributes per-block, which can cause each thread to block on the
getAttributesmethod. It is also noticeable when creating many readers/writers at the same location, as the lock get block ongetVersionduring construction.Ensuring the the N5Reader/Writer is using a gson cache solves this in part, but the underlying problem still persists. In large parallel environments, where it is difficult to re-use the N5Reader/Writer instance across threads (e.g. when using Spark) this can be particularly harmful, and either require explicit logic to share the cache across threads on the same JVM, or result in effectively single-thread read performance.
A solution would be to implement proper ReadWriteLock access.