This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 74b098e9839 Fix HTTP 500 in filestore getMetadata racing with 
concurrent delete (#4367)
74b098e9839 is described below

commit 74b098e9839ba8739b5ec402c460092bec4c551b
Author: Eric Pugh <[email protected]>
AuthorDate: Sat May 2 10:18:18 2026 -0400

    Fix HTTP 500 in filestore getMetadata racing with concurrent delete (#4367)
---
 .../PR#4367-filestore-getmetadata-delete-race.yml    |  7 +++++++
 .../org/apache/solr/filestore/ClusterFileStore.java  | 20 ++++++++++++++++----
 .../org/apache/solr/filestore/DistribFileStore.java  |  7 +++++++
 3 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/changelog/unreleased/PR#4367-filestore-getmetadata-delete-race.yml 
b/changelog/unreleased/PR#4367-filestore-getmetadata-delete-race.yml
new file mode 100644
index 00000000000..96be57260aa
--- /dev/null
+++ b/changelog/unreleased/PR#4367-filestore-getmetadata-delete-race.yml
@@ -0,0 +1,7 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Filestore metadata API no longer returns HTTP 500 when a file is 
deleted concurrently with a metadata read; the response now matches the 
not-found case (null entry).
+type: fixed # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
+authors:
+  - name: Eric Pugh
+links: 
+  - https://github.com/apache/solr/pull/4367
diff --git a/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java 
b/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java
index c405fcbcfe9..bcd4e562053 100644
--- a/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java
+++ b/solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java
@@ -31,6 +31,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.solr.api.JerseyResource;
@@ -228,13 +229,14 @@ public class ClusterFileStore extends JerseyResource 
implements ClusterFileStore
         String parentPath = path.substring(0, path.lastIndexOf('/'));
         List<FileStore.FileDetails> l = fileStore.list(parentPath, s -> 
s.equals(fileName));
 
-        dirListingResponse.files =
-            Collections.singletonMap(path, l.isEmpty() ? null : 
convertToResponse(l.get(0)));
+        FileStoreEntryMetadata entry = l.isEmpty() ? null : 
convertToResponse(l.get(0));
+        dirListingResponse.files = Collections.singletonMap(path, entry);
         break;
       case DIRECTORY:
         final var directoryContents =
             fileStore.list(path, null).stream()
                 .map(details -> convertToResponse(details))
+                .filter(Objects::nonNull)
                 .collect(Collectors.toList());
         dirListingResponse.files = Map.of(path, directoryContents);
         break;
@@ -254,8 +256,18 @@ public class ClusterFileStore extends JerseyResource 
implements ClusterFileStore
       return entryMetadata;
     }
 
-    entryMetadata.size = details.size();
-    entryMetadata.timestamp = details.getTimeStamp();
+    long size = details.size();
+    if (size < 0) {
+      // File was deleted concurrently between listing and reading its 
attributes.
+      return null;
+    }
+    final var timestamp = details.getTimeStamp();
+    if (timestamp == null) {
+      // File was deleted concurrently between reading its size and timestamp.
+      return null;
+    }
+    entryMetadata.size = size;
+    entryMetadata.timestamp = timestamp;
     if (details.getMetaData() != null) {
       details.getMetaData().toMap(entryMetadata.unknownProperties());
     }
diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java 
b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java
index 398075663a4..7fffd9ebf08 100644
--- a/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java
+++ b/solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java
@@ -30,6 +30,7 @@ import java.nio.ByteBuffer;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
@@ -288,6 +289,9 @@ public class DistribFileStore implements FileStore {
         public Date getTimeStamp() {
           try {
             return new Date(Files.getLastModifiedTime(realPath()).toMillis());
+          } catch (NoSuchFileException e) {
+            // File was deleted concurrently between listing and reading its 
attributes.
+            return null;
           } catch (IOException e) {
             throw new SolrException(
                 SERVER_ERROR, "Failed to retrieve the last modified time for: 
" + realPath(), e);
@@ -303,6 +307,9 @@ public class DistribFileStore implements FileStore {
         public long size() {
           try {
             return Files.size(realPath());
+          } catch (NoSuchFileException e) {
+            // File was deleted concurrently between listing and reading its 
attributes.
+            return -1;
           } catch (IOException e) {
             throw new SolrException(
                 SERVER_ERROR, "Failed to retrieve the file size for: " + 
realPath(), e);

Reply via email to