NIO source code analysis - FileChannel high-level knowledge points map, transferTo and transferFrom

Posted by chrishide87 on Sat, 11 Sep 2021 19:05:09 +0200

preface:

    Above, we introduced the basic API usage of FileChannel. In this article, let's take a look at the high-level API in FileChannel.

     It's high-level. Really, these knowledge points make a lot of use of the advanced playing method of file transfer mapping of the operating system, which greatly improves the efficiency of our file operation. kafka and rocketMQ, which we are familiar with, also use these high-level API s to achieve such high efficiency.

     We propose a requirement, which is described as follows: provide an external socket service, which is to obtain the files in the specified file directory, write them into the socket, and finally display them on the client side.

1. Traditional file network transmission process

    According to this requirement, we use the following code to complete it in a conventional way:

File file = new File("D:\\test.txt");
Long size = file.length();
byte[] arr = new byte[size.intValue()];

try {
    // 1. Read the contents of test.txt file into arr
    FileInputStream fileInputStream = new FileInputStream(file);
    fileInputStream.read(arr);

    // 2. Provision of external services
    Socket socket = new ServerSocket(9999).accept();

    // 3. Transfer to client
    socket.getOutputStream().write(arr);
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

The above is an implementation of the simplest version.

So from the perspective of the operating system, what are the above transmission processes?

The process can be divided into the following steps:
The fileInputStream.read method corresponds to:
1) The first copy: the read method is called, and the user state is switched to the kernel state. The data is copied from the hard disk to the kernel buffer, which is based on DMA automatic operation and does not need CPU support
2) The second copy: copy from the kernel buffer to the user buffer (that is, byte[] arr). The read method returns, using the conversion from kernel state to user state.
socket.getOutputStream().write(arr) corresponds to:
3) The third copy: copy data from the user buffer to the kernel buffer of the socket. The write method is called to switch from user mode to kernel mode.
4) The data is copied from the socket kernel buffer to the network protocol engine using DMA. The write method returns, and the kernel state is switched to the user state.
From the above process, we can find that there are four copies of data and four context switches.
So is there any optimization method? The answer is yes, let's move on.

2.mmap optimization

     mmap maps files directly into memory through memory mapping. At this time, user space and kernel space can share the contents of this memory space. The user's modification of the memory content can be directly fed back to the disk file.
FileChannel provides a map method to implement the mmap function
File file = new File("D:\\test.txt");
Long size = file.length();
byte[] arr = new byte[size.intValue()];

try {
    // 1. Read the contents of test.txt file into arr
    RandomAccessFile raFile = new RandomAccessFile(file, "rwd");
    FileChannel channel = raFile.getChannel();
    MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);

    // 2. Provision of external services
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    serverSocketChannel.configureBlocking(false);

    while(true){
        SocketChannel socketChannel =
            serverSocketChannel.accept();

        if(socketChannel != null){
            // 3. Transfer to client
            socketChannel.write(mappedByteBuffer);
        }
    }

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
We directly map the contents of file to mappedByteBuffer, and then directly transfer the contents of mappedByteBuffer.
So from the perspective of the operating system, what are the above transmission processes?

 

Refer to the four steps in 1. One memory copy is missing, that is, copying files from the kernel buffer to the user process buffer; However, context switching has not decreased.

3.sendFile optimization (Linux version 2.1)

The sendFile function is provided in Linux version 2.1. What are the optimizations of this function for this example?
That is, the data can be transferred directly from the kernel file buffer to the Socket buffer without going through the user state
 
FileChannel provides transferTo (and transferFrom) methods to implement the sendFile function
File file = new File("D:\\test.txt");
Long size = file.length();

try {
    // 1. Read the contents of test.txt file into arr
    RandomAccessFile raFile = new RandomAccessFile(file, "rwd");
    FileChannel channel = raFile.getChannel();

    // 2. Provision of external services
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    serverSocketChannel.configureBlocking(false);

    while(true){
        SocketChannel socketChannel =
            serverSocketChannel.accept();

        if(socketChannel != null){
            // 3. Use the transferTo method to transfer the file data to the client
            channel.transferTo(0, size, socketChannel);
        }
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
The code in the same 2 only uses a different method when transferring the file content to the socket in the last step. In this example, the FileChannel.transferTo method is used to transfer data.
So from the perspective of the operating system, what are the above transmission processes?

 

Referring to the four processes in 1, without the participation of user space, there is no switching between user state and kernel state.
Therefore, to sum up, it reduces two context switches and one data copy at the same time.
Note: which two context switches are left? The user process calls the transferTo method to switch the user state to the kernel state; Call the method to return and switch from kernel mode to user mode.

4.sendFile optimization (Linux version 2.4)

    In Linux version 2.4, sendFile is optimized to avoid copying from the kernel file buffer to the Socket buffer, and directly to the network card, reducing one copy again.
The code is the same as 3, but the operating system is different.
So from the perspective of operating system, what process has its transmission gone through?

 

Referring to the four operation processes in 1, there is also less user space participation, and there is no switching between user state and kernel state.

So to sum up, there are two data copies and two context switches (compared with 3, the copy from the kernel file buffer to the kernel socket buffer is reduced)

Summary:

    Let's show the similarities and differences of the above four transmission modes through a chart

transmission modeContext switching timesNumber of data copies
Traditional IO mode44
mmap mode43
sendFile(Linux2.1)23
sendFile(Linux2.4)22
In fact, the above sendFile data transmission method is what we often call zero copy.
There may be some questions. Even if the sendFile function in Linux version 2.4 has two data copies, why is it said to be zero copy?
The author copied a paragraph and explained it very interesting:
First, we say zero copy from the perspective of the operating system. Because no data is duplicated between kernel buffers (only kernel buffer There's a piece of data,
sendFile 2.1 The version actually has 2 copies of data, which is not zero copy). For example, in our initial example, the kernel cache and Socket The data in the buffer is duplicated.

Zero copy not only brings less data replication, but also other performance advantages, such as less context switching and less CPU Cache pseudo sharing and none CPU Checksum calculation.
A little more mmap and sendFile The difference.

reference resources:

mmap and zero copy technology under linux

mmap and sendfile() - short book

 

Topics: Java