Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOLR-16903: Migrate off java.io.File to java.nio.file.Path from core files #2924

Merged
merged 10 commits into from
Feb 1, 2025

Conversation

mlbiscoc
Copy link
Contributor

https://issues.apache.org/jira/browse/SOLR-16903

Description

Still in draft. Tests seem to pass locally but a lot can still be refactored better around Path.

This should remove all imports of java.io.File inside main core files. This excludes test files as there are too many changes to include into this PR and will make that in a separate PR.

Solution

Found where import java.io.File; was being used and migrated logic to java.nio.file.Path as best as possible.

Tests

Tests pass locally

Checklist

Please review the following and check all that apply:

  • I have reviewed the guidelines for How to Contribute and my code conforms to the standards described there to the best of my ability.
  • I have created a Jira issue and added the issue ID to my pull request title.
  • I have given Solr maintainers access to contribute to my PR branch. (optional but recommended, not available for branches on forks living under an organisation)
  • I have developed this patch against the main branch.
  • I have run ./gradlew check.
  • I have added tests for my changes.
  • I have added documentation for the Reference Guide

@@ -64,7 +63,7 @@ public class CoreDescriptor {
public static final String SOLR_CORE_PROP_PREFIX = "solr.core.";

public static final String DEFAULT_EXTERNAL_PROPERTIES_FILE =
"conf" + File.separator + "solrcore.properties";
Path.of("conf/solrcore.properties").toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any chance of different file seperators? I wasn't sure if that was one reason for using the File.separator, like on windows? Or is that one of the benefits of Path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was worried about this so started reading Path.of() documentation and oracle documentation. Filesystems.getDefault().getPath(String) which should return the OS path and developers can use the standard / regardless. It's also a benefit of Path for Solr to no longer have to do all these File.separator chars or OS checking...

I haven't actually tested this on something like a windows operating system to confirm though...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really great benefit of the migration!

@mlbiscoc mlbiscoc marked this pull request as ready for review December 24, 2024 17:48
Copy link
Contributor Author

@mlbiscoc mlbiscoc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is ready for review

Comment on lines 1362 to 1370
try {
totalSpace = Files.getFileStore(dataDirFile).getTotalSpace();
useableSpace = Files.getFileStore(dataDirFile).getUsableSpace();
} catch (Exception e) {
// TODO Metrics used to default to 0 with java.io.File even if directory didn't exist
// Should throw an exception and initialize data directory before metrics
totalSpace = 0L;
useableSpace = 0L;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This here was questionable. Upon a Solr core being initialized, metrics was trying to calculate and initialize a gauge for the data/ directories before the directory was ever created. This always failed with File but it defaults to 0. Path on the other hand throws an Exception. This didn't seem right but also moving where the initializeMetrics is called in a bunch of different places had tests failing and I wasn't sure why so I kept it as TODO.

But also if this is initializing metrics for a SolrCore registry upon creation, shouldn't it always be 0 as the data directory was most likely just created?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not pre-compute this stuff; it should only be calculated/fetched when the metric is fetched. Maybe could clarify that the TODO is to move metrics initialization to after data directory initialization, thus avoiding this exception (hopefully) but that may not be entirely possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just initialized the gauges to 0 and added the TODO. Could be worth moving metric initialization to after the directory is created if we want that data point of the disk usage.

Copy link
Contributor

@epugh epugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great progress here! I've been poking a bit around the FIleStore stuff, so great to see some of the improvements in that area as well. I put in a bunch of feedback, I hope it's useful. Ping me when you are ready for final review!

@@ -63,5 +64,6 @@ SolrJerseyResponse getFile(
String getFrom,
@Parameter(description = "Indicates that (only) file metadata should be fetched")
@QueryParam("meta")
Boolean meta);
Boolean meta)
throws IOException;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to confirm this throw was needed? Maybe because of something else furthur down?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually no it isn't needed. It was due to my changes on List<FileDetails> list() method under DistribFileStore so I threw a SolrException instead which seems correct.

@@ -64,7 +63,7 @@ public class CoreDescriptor {
public static final String SOLR_CORE_PROP_PREFIX = "solr.core.";

public static final String DEFAULT_EXTERNAL_PROPERTIES_FILE =
"conf" + File.separator + "solrcore.properties";
Path.of("conf/solrcore.properties").toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really great benefit of the migration!

return (path != null && (!(path.endsWith("/") || path.endsWith("\\"))))
? path + File.separator
: path;
return (path != null && (!(path.endsWith("/") || path.endsWith("\\")))) ? path + "/" : path;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow that's gnarly.. Is there no existing normalize() function in any of our jars that would do this for us? I guess fixing that is orthongonal to this effort....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code was fine as it was but perhaps got your attention because File is referenced. Since we only need to know the separator, try FileSystems.getDefault().getSeparator()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking, we shouldn't need to call FileSystems.getDefault().getSeparator() assuming callers of this eventually take this string and put it into a Path, but I don't think that is necessarily true. Seeing something like this line it's comparing strings 1:1 but my slash would probably break it on a different OS that uses a different delimiter. Directory strings should probably be checked through Path.equal(), not strings directly. I just put it back with FileSystems.getDefault().getSeparator()

if (Files.isDirectory(f)) {
fileInfo.add("directory", true);
} else {
// TODO? content type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets. get rid of this todo.. this code hasn't changed in years, and if someone wants it they can add it later! we shouldn't litter our code with todos that are mostly ideas.. a todo really implies hey, someone SHOULD go do this very soon!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Removed it. Mostly trying to just untouch code unless needed so was just porting over anything including TODO's. Let me know if there is more that should be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An aside: The question mark there definitely doesn't convey the urgency that Eric suggests. There just isn't a universal interpretation of TODOs across projects (sadly).

@@ -84,7 +83,7 @@ public String init(NamedList<?> config, SolrCore core) {
// If indexDir is relative then create index inside core.getDataDir()
if (indexDir != null) {
if (!Path.of(indexDir).isAbsolute()) {
indexDir = core.getDataDir() + File.separator + indexDir;
indexDir = Path.of(core.getDataDir(), indexDir).toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can indexDir be a path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Changed it as Path.

@@ -89,7 +88,7 @@ public Lookup create(NamedList<?> params, SolrCore core) {
String indexPath =
params.get(INDEX_PATH) != null ? params.get(INDEX_PATH).toString() : DEFAULT_INDEX_PATH;
if (!Path.of(indexPath).isAbsolute()) {
indexPath = core.getDataDir() + File.separator + indexPath;
indexPath = Path.of(core.getDataDir(), indexPath).toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can indexPath be a Path? Also, is there an opportunity to align variable naming between indexPath and the use of indexDir in in AbstractLuceneSpellChecker?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes good catch. Much better than calling Path.of everywhere.

}
}

is = new FileInputStream(f);
is = new FileInputStream(f.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files.newInputStream() instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added TODO. Might either make another story or just PR to move them all. I see about 34 instances of this used including inside of tests (which is a whole different monster 😵‍💫) but at least after this PR, there should be no uses of File in Solr itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sympathize with wanting to keep the scope of this PR in-check. But here, we are talking about how to go from Path to an InputStream _for the very lines you are editing) (since lines like this previously didn't have a Path but now do). So I think it's in scope here. We're not talking about a full search of every case where we could use Files.newInputStream but didn't yet. It's just for the lines you are already editing. No new lines of code; no complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats fair. I had a previous comment where I said the change wasn't 1:1 but here it is. Wasn't sure what I ran into then but for the PR where I changed to Path and there is a new FileInputStream I changed the new FileInputStream to Files.newInputStream(). We can tackle the rest in another.

} catch (Exception e) {
// swallow exception for now
}
}

// allow exception to be thrown from the final try.
if (is == null) {
is = new FileInputStream(f);
is = new FileInputStream(f.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files.newInputStream?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got half way through review today.

@@ -121,7 +120,7 @@ public InputStream openResource(String resource) throws IOException {

try {
// delegate to the class loader (looking into $INSTANCE_DIR/lib jars)
is = classLoader.getResourceAsStream(resource.replace(File.separatorChar, '/'));
is = classLoader.getResourceAsStream(Path.of(resource).toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that actually works, I think a little comment is needed like "normalize path separator"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I think it doesn't work; not on Windows. I thought I commented elsewhere in that lengthy review that all Path.of(resource).toString() that you are adding is probably flawed

Comment on lines 99 to 98
CORE_DATADIR, "data" + File.separator,
CORE_DATADIR, Path.of("data/").toString(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trailing slash should ideally not be necessary. I'd prefer to just drop it and we deal with the consequences. If needed, the previous code was clearer IMO so I'd rather see something similarly clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Comment on lines 1124 to 1125
// initialize core metrics
initializeMetrics(solrMetricsContext, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you move this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a mistake. I forgot to revert. This has to do with metrics being pre-computed with File disk usage and was trying to get the data directory initialized before the metrics registered. I eventually stopped and forgot to move it back

if (isMetaDataFile(simpleName)) {
try (InputStream is = new FileInputStream(file)) {
try (InputStream is = new FileInputStream(file.toString())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes Eric is right but may want to do that universally in another PR to avoid scope creep.

Comment on lines 360 to 359
info.add("dataDir", normalizePath(core.getDataDir()));
info.add("dataDir", Path.of(core.getDataDir()).toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm suspicious of this technique. I'd prefer we have a utility method to make certain normalizations when they are needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely removed that normalizePath because I thought Path would do this for us already, so the utility wasn't needed. Happy to bring it back though then I guess keep the code as it was?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like normalizePath(...) because it communicates an intention that your one-liner certainly doesn't. I guess you could edit the method to have this line of code that you think is equivalent, + comments indicating that it (not so obviously) changes path separators. I wish I had a Windows machine handy to tinker with Path to verify this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you bring the method back please? In a file utility place, and documenting what sort of normalization it does (otherwise is ambiguous). Like; normalizeToOsPathSeparator(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a place in FileUtils and brought it back. Also just switched to FileSystems.getDefault().getSeparator() and brought all the logic to be careful of regressions since it seems neither of us can confirm fully on a windows machine.

NamedList<SimpleOrderedMap<Object>> files = new SimpleOrderedMap<>();
for (File f : adminFile.listFiles()) {
String path = f.getAbsolutePath().substring(basePath);
path = path.replace('\\', '/'); // normalize slashes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't lose this. I feel like we need a toForwardSlashPathString(Path) utility method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this method itself, I don't think it should need it, but you just want the method itself in Solr for other use-cases?
I created a static toForwardSlashPathString method in this class. Maybe it belongs or we could put it in FileUtils.java?

What are scenarios are does Solr need this method?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I agree that the ShowFileRequestHandler ought not to be receiving backslashes.

@github-actions github-actions bot removed the cat:api label Jan 16, 2025
Copy link
Contributor Author

@mlbiscoc mlbiscoc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through all the comments and changed them as best I could. Had some questions on a few which I replied back, but overall wasn't too bad. Tests pass locally again but ready for another round of review.

@@ -63,5 +64,6 @@ SolrJerseyResponse getFile(
String getFrom,
@Parameter(description = "Indicates that (only) file metadata should be fetched")
@QueryParam("meta")
Boolean meta);
Boolean meta)
throws IOException;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually no it isn't needed. It was due to my changes on List<FileDetails> list() method under DistribFileStore so I threw a SolrException instead which seems correct.

@@ -121,7 +120,7 @@ public InputStream openResource(String resource) throws IOException {

try {
// delegate to the class loader (looking into $INSTANCE_DIR/lib jars)
is = classLoader.getResourceAsStream(resource.replace(File.separatorChar, '/'));
is = classLoader.getResourceAsStream(Path.of(resource).toString());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment on lines 99 to 98
CORE_DATADIR, "data" + File.separator,
CORE_DATADIR, Path.of("data/").toString(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Comment on lines 1124 to 1125
// initialize core metrics
initializeMetrics(solrMetricsContext, null);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a mistake. I forgot to revert. This has to do with metrics being pre-computed with File disk usage and was trying to get the data directory initialized before the metrics registered. I eventually stopped and forgot to move it back

if (Files.isDirectory(f)) {
fileInfo.add("directory", true);
} else {
// TODO? content type
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Removed it. Mostly trying to just untouch code unless needed so was just porting over anything including TODO's. Let me know if there is more that should be removed.

@@ -84,7 +83,7 @@ public String init(NamedList<?> config, SolrCore core) {
// If indexDir is relative then create index inside core.getDataDir()
if (indexDir != null) {
if (!Path.of(indexDir).isAbsolute()) {
indexDir = core.getDataDir() + File.separator + indexDir;
indexDir = Path.of(core.getDataDir(), indexDir).toString();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Changed it as Path.

@@ -89,7 +88,7 @@ public Lookup create(NamedList<?> params, SolrCore core) {
String indexPath =
params.get(INDEX_PATH) != null ? params.get(INDEX_PATH).toString() : DEFAULT_INDEX_PATH;
if (!Path.of(indexPath).isAbsolute()) {
indexPath = core.getDataDir() + File.separator + indexPath;
indexPath = Path.of(core.getDataDir(), indexPath).toString();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes good catch. Much better than calling Path.of everywhere.

}
}

is = new FileInputStream(f);
is = new FileInputStream(f.toString());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added TODO. Might either make another story or just PR to move them all. I see about 34 instances of this used including inside of tests (which is a whole different monster 😵‍💫) but at least after this PR, there should be no uses of File in Solr itself.

} catch (Exception e) {
// swallow exception for now
}
}

// allow exception to be thrown from the final try.
if (is == null) {
is = new FileInputStream(f);
is = new FileInputStream(f.toString());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above

Copy link
Contributor

@epugh epugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM pending the tests... I just kicked precommit and solr tests off on github.

I do hope you have the energy to do this on tests too!

@dsmiley
Copy link
Contributor

dsmiley commented Jan 16, 2025

As a general comment, I want to ensure we're careful converting some Strings to Paths. It's only safe if we're certain that it's exactly a file system path. Paths resolved inside a DirectoryFactory/Directory are not necessarily literally on the file system (it's an abstraction to data that could be in HDFS or S3 or...). It'd be nice to use a Path for this anyway but shouldn't be without a custom FileSystem impl (very out of scope here). Same for ZK paths. Also some of our HTTP APIs are file-system inspired (ConfigSet, FileStore, ...) with paths in which '/' is the separator no matter what the underlying file system is Solr is running on (after all; don't want the client to care about the OS Solr is running on). These are not directly convertible to a Path either, or at least take some work to do separator translation if the end location is on-disk (file store & file system ConfigSetService).

solr/core/src/java/org/apache/solr/util/VersionedFile.java Outdated Show resolved Hide resolved
SolrException.ErrorCode.SERVER_ERROR, "Unable to list files in " + dir, e);
}

f = Path.of(dir.toString(), fileList.getLast().getFileName().toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use Path.of when you already have Path instances to work with. Path.of is for when you have Strings (not Paths).
I think this line of code should simply be dir.resolve(fileList.getLast())

}
}

is = new FileInputStream(f);
is = new FileInputStream(f.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sympathize with wanting to keep the scope of this PR in-check. But here, we are talking about how to go from Path to an InputStream _for the very lines you are editing) (since lines like this previously didn't have a Path but now do). So I think it's in scope here. We're not talking about a full search of every case where we could use Files.newInputStream but didn't yet. It's just for the lines you are already editing. No new lines of code; no complexity.

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the whole thing again.

() -> dataDirFile.getTotalSpace(), true, "totalSpace", Category.CORE.toString(), "fs");
parentContext.gauge(
() -> dataDirFile.getUsableSpace(), true, "usableSpace", Category.CORE.toString(), "fs");
Path dataDirFile = Paths.get(dataDir);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really minor but I think dataDirPath is a better name

solr/core/src/java/org/apache/solr/core/SolrCore.java Outdated Show resolved Hide resolved
@@ -94,7 +94,7 @@ public static void assertNoPathTraversal(Path pathToAssert) {

/** Asserts that a path is not a Windows UNC path */
public static void assertNotUnc(Path pathToAssert) {
if (OS.isFamilyWindows() && pathToAssert.toString().startsWith("\\\\")) {
if (OS.isFamilyWindows() || pathToAssert.toString().startsWith("\\\\")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but OR means that this would consistently fail on Windows even if the path isn't UNC

Comment on lines 360 to 359
info.add("dataDir", normalizePath(core.getDataDir()));
info.add("dataDir", Path.of(core.getDataDir()).toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you bring the method back please? In a file utility place, and documenting what sort of normalization it does (otherwise is ambiguous). Like; normalizeToOsPathSeparator(...)

NamedList<SimpleOrderedMap<Object>> files = new SimpleOrderedMap<>();
for (File f : adminFile.listFiles()) {
String path = f.getAbsolutePath().substring(basePath);
path = path.replace('\\', '/'); // normalize slashes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I agree that the ShowFileRequestHandler ought not to be receiving backslashes.

@epugh
Copy link
Contributor

epugh commented Jan 31, 2025

Thank you @dsmiley for digging through things. Your comments and eyes is probably saving us a lot of test failures down the road ;-).

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! You can update CHANGES.txt for the existing SOLR-16903 to combine it. I think as other PRs happen, it'll ultimately be a broad File -> Path with a list of contributors.

@dsmiley dsmiley merged commit b32b675 into apache:main Feb 1, 2025
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants