Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
20 changes: 16 additions & 4 deletions solr/core/src/java/org/apache/solr/filestore/ClusterFileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
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;
Expand Down Expand Up @@ -228,13 +229,14 @@ public static FileStoreDirectoryListingResponse getMetadata(
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;
Expand All @@ -254,8 +256,18 @@ private static FileStoreEntryMetadata convertToResponse(FileStore.FileDetails de
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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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;
Expand Down Expand Up @@ -288,6 +289,9 @@ public MetaData getMetaData() {
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);
Expand All @@ -303,6 +307,9 @@ public boolean isDir() {
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);
Expand Down
Loading