Search code examples
javaunixfilesystemsnio

Java File.renameTo() Implementation for UnixFileSystem


I was trying to figure how File.renameTo() works in Java and I reached the following method in UnixFileSystem.java (I'm on macOS).

private native boolean rename0(File f1, File f2);

I understand that (please correct if I'm wrong) native means JVM calls code/library written in another language. So, where/how can I or if it's possible see its implementation?

I'm curious to see its implementation as to confirm if I can use it for my following use case.

I need to run a Java application in two (or more) different servers which poll for files in the same directory (shared filesystem) and only one instance (server) should process a particular file. Whenever the application in any of the servers sees a file, it tries to move to some other directory and if the move is successful (determined by boolean returned by File.renameTo() method), that server start processing on those file contents (batch processing to be precise). I did a quick test with three different instances polling a single directory (generating new files at 1000 files per second) and the results were as expected. I just want to confirm if it scales.

Note that I'm not moving the actual file but a zero-byte file named something like <actual-filename>.DONE which is created after copying the file from source is complete.


Solution

  • AFAIK, Source of OpenJDK and Orale JDK are almost the same. Therefore, you can find implementation of rename0 here:

    #include <stdlib.h>
    
    JNIEXPORT jboolean JNICALL
    Java_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
                                        jobject from, jobject to)
    {
        jboolean rv = JNI_FALSE;
    
        WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
            WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
                if (rename(fromPath, toPath) == 0) {
                    rv = JNI_TRUE;
                }
            } END_PLATFORM_STRING(env, toPath);
        } END_PLATFORM_STRING(env, fromPath);
        return rv;
    }
    

    You can see that it's actually calling libc's rename. Since most of the environment uses glibc, here's the document:

    One useful feature of rename is that the meaning of newname changes “atomically” from any previously existing file by that name to its new meaning (i.e., the file that was called oldname). There is no instant at which newname is non-existent “in between” the old meaning and the new meaning. If there is a system crash during the operation, it is possible for both names to still exist; but newname will always be intact if it exists at all.

    Maybe your code is safe as long as it does not crash, and filesystem is working fine. However It may depend on what filesystem you are using (e.g. nfs).

    There's good another question in stackoverflow, so it may help.