Fix AtomicFile FileNotFoundException when a namepace is being accessed concurrently. - #102
Fix AtomicFile FileNotFoundException when a namepace is being accessed concurrently. #102TonyTangAndroid wants to merge 26 commits into
Conversation
| private FileOutputStream createParentLegacy(FileNotFoundException e) throws IOException { | ||
| File parent = mNewName.getParentFile(); | ||
| if (!parent.mkdirs()) { | ||
| throw new IOException("Failed to create directory for " + mNewName); | ||
| } | ||
| try { | ||
| return new FileOutputStream(mNewName); | ||
| } catch (FileNotFoundException e2) { | ||
| throw new IOException("Failed to create new file " + mNewName, e2); | ||
| } | ||
| } |
There was a problem hiding this comment.
Those are exactly the same code that are on PROD right now.
| synchronized (lock) { | ||
| if (!parent.exists() && !parent.mkdirs()) { | ||
| throw rawError; | ||
| } |
There was a problem hiding this comment.
Those are the core code to make the fix effective. One should be noted that synchronized will only be applied when the folder was missing. If the folder is already present, then those piece of code will no longer be executed again.
TonyTangAndroid
left a comment
There was a problem hiding this comment.
Add comments to highlight the changes in fixing the FileNotFoundException
| if (fixOnFileNotFoundationException) { | ||
| return createParentWithFix(rawError); | ||
| } else { | ||
| return createParentLegacy(rawError); | ||
| } | ||
| } |
There was a problem hiding this comment.
We are to conduct the clean up once we confirm the fix is effective or even apply the legacy branch again if we could figure out the higher level root cause.
TonyTangAndroid
left a comment
There was a problem hiding this comment.
Apply java.nio.file.Files.createDirectories
|
Abort this pull request for now to apply Files.createDirectories without concurrent fix |
This pull request aims to fix the
FileNotFoundExceptiontriggered when the namespace being created and accessed concurrently for the first time.Given the following sample code to create a
PrimitiveSimpleStoreinstance,whenever
PrimitiveSimpleStore#putStringis executed for the first time, it will implicitly trigger the detected code inAtomicFile. At this time, the parent folder ofmNewNameis657b3cd7-f689-451b-aca0-628de60aa234and it is not created, hence, the first expectedFileNotFoundExceptionis triggered. However, there could be two thread concurrently trigger such error, which leads both thread to execute the statementparent.mkdirs(), which results in either one of them failure increate directory.To validate this theory, dedicated test code
AtomicFileConcurrentTesthas been written to reproduce the error and fix the issue.For more details, please refer to the test code to highlight the difference.
One should be noted There are a lot of trial and error in the process of reproducing the issues and fixing the issue, it is recommended for the reviewers to squash all the commits as one commit when it is to be merged. This way, the commit history will remain to be clean.