apache / apache/lucene

FileExistsCachingDirectory, to work around unreliable File.exists [LUCENE-5541]

Open
#6,604 5 comments 0 reactions 0 assignees View on GitHub
legacy-jira-priority:Major module:core/store type:bug
Dominant language
Java
Stars
3.6k
Forks
1.4k
Avg merge
2d 11h
Merged PRs (30d)
88

Description

File.exists is a dangerous method in Java, because if there is a
low-level IOException (permission denied, out of file handles, etc.)
the method can return false when it should return true.

Fortunately, as of Lucene 4.x, we rely much less on File.exists,
because we track which files the codec components created, and we know
those files then exist.

But, unfortunately, going from 3.0.x to 3.6.x, we increased our
reliance on File.exists, e.g. when creating CFS we check File.exists
on each sub-file before trying to add it, and I have a customer
corruption case where apparently a transient low level IOE caused
File.exists to incorrectly return false for one of the sub-files. It
results in corruption like this:

```
java.io.FileNotFoundException: No sub-file with id .fnm found (fileName=_1u7.cfs files: [.tis, .tii, .frq, .prx, .fdt, .nrm, .fdx])
org.apache.lucene.index.CompoundFileReader.openInput(CompoundFileReader.java:157)
org.apache.lucene.index.CompoundFileReader.openInput(CompoundFileReader.java:146)
org.apache.lucene.index.FieldInfos.(FieldInfos.java:71)
org.apache.lucene.index.IndexWriter.getFieldInfos(IndexWriter.java:1212)
org.apache.lucene.index.IndexWriter.getCurrentFieldInfos(IndexWriter.java:1228)
org.apache.lucene.index.IndexWriter.(IndexWriter.java:1161)
```

I think typically local file systems don't often hit such low level
errors, but if you have an index on a remote filesystem, where network
hiccups can cause problems, it's more likely.

As a simple workaround, I created a basic Directory delegator that
holds a Set of all created but not deleted files, and short-circuits
fileExists to return true if the file is in that set.

I don't plan to commit this: we aren't doing bug-fix releases on
3.6.x anymore (it's very old by now), and this problem is already
"fixed" in 4.x (by reducing our reliance on File.exists), but I wanted
to post the code here in case others hit it. It looks like it was hit
e.g. https://netbeans.org/bugzilla/show_bug.cgi?id=189571 and
https://issues.jboss.org/browse/ISPN-2981

---
Migrated from [LUCENE-5541](https://issues.apache.org/jira/browse/LUCENE-5541) by Michael McCandless (@mikemccand), updated Sep 17 2014
Attachments: [LUCENE-5541.patch](https://apache.github.io/lucene-jira-archive/attachments/LUCENE-5541/LUCENE-5541.patch)

Contributor guide

Open the contributing guide

Research direction

The report names CompoundFileReader.openInput and the File.exists checks involved in compound-file creation, but gives no current source path or test. Start by locating those entry points and checking whether the 4.x behavior still applies; the issue does not define a current change or a verifiable done condition.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, search
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
18/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.