├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── moe │ └── cnkirito │ └── kdio │ ├── DirectChannel.java │ ├── DirectChannelImpl.java │ ├── DirectIOLib.java │ ├── DirectIOTestMain.java │ ├── DirectIOUtils.java │ ├── DirectRandomAccessFile.java │ └── OpenFlags.java └── test └── java └── moe └── cnkirito └── kdio └── DirectIOTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | target/ 3 | *.jar 4 | !.mvn/wrapper/* 5 | *.war 6 | *.zip 7 | *.tar 8 | *.tar.gz 9 | 10 | # eclipse ignore 11 | .settings/ 12 | .project 13 | .classpath 14 | 15 | # idea ignore 16 | .idea/ 17 | *.ipr 18 | *.iml 19 | *.iws 20 | 21 | # temp ignore 22 | *.log 23 | *.cache 24 | *.diff 25 | *.patch 26 | *.tmp 27 | 28 | # system ignore 29 | .DS_Store 30 | Thumbs.db 31 | *.orig 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 xujingfeng (kirito.moe@foxmail.com) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project 2 | 3 | A Java Direct IO framework which is very simple to use. 4 | 5 | # Add to your project 6 | 7 | ```xml 8 | 9 | moe.cnkirito.kdio 10 | kdio-core 11 | 1.0.0 12 | 13 | ``` 14 | 15 | # Sample 16 | 17 | ### Notice 18 | 19 | ``` 20 | // file path should be specific since the different file path determine whether your system support direct io 21 | public static DirectIOLib directIOLib = DirectIOLib.getLibForPath("/"); 22 | // you should always write into your disk the Integer-Multiple of block size through direct io. 23 | // in most system, the block size is 4kb 24 | private static final int BLOCK_SIZE = 4 * 1024; 25 | ``` 26 | 27 | > Usually, only specific linux system support direct io. You should own a linux server. 28 | 29 | ### Write 30 | 31 | ```java 32 | private static void write() throws IOException { 33 | if (DirectIOLib.binit) { 34 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 35 | for (int i = 0; i < BLOCK_SIZE; i++) { 36 | byteBuffer.putInt(i); 37 | } 38 | byteBuffer.flip(); 39 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 40 | directRandomAccessFile.write(byteBuffer, 0); 41 | } else { 42 | throw new RuntimeException("your system do not support direct io"); 43 | } 44 | } 45 | ``` 46 | 47 | ### Read 48 | 49 | ```java 50 | public static void read() throws IOException { 51 | if (DirectIOLib.binit) { 52 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 53 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 54 | directRandomAccessFile.read(byteBuffer, 0); 55 | byteBuffer.flip(); 56 | for (int i = 0; i < BLOCK_SIZE; i++) { 57 | System.out.print(byteBuffer.getInt() + " "); 58 | } 59 | } else { 60 | throw new RuntimeException("your system do not support direct io"); 61 | } 62 | } 63 | ``` 64 | 65 | ### Install & Run 66 | 67 | ``` 68 | mvn clean install -DskipTests 69 | ``` 70 | 71 | you will get the sample of direct io test: DirectIOTest.jar 72 | 73 | deploy it to a linux server and use 74 | 75 | ```java 76 | java -jar DirectIOTest.jar 77 | ``` 78 | 79 | you can try it. 80 | 81 | # License 82 | 83 | kdio is under the Apache 2.0 license. -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | moe.cnkirito.kdio 8 | kdio-core 9 | 1.0.2 10 | 11 | 12 | UTF-8 13 | 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 1.8 22 | 1.8 23 | 24 | 25 | 26 | maven-assembly-plugin 27 | 2.2.1 28 | 29 | 30 | 31 | moe.cnkirito.kdio.DirectIOTestMain 32 | 33 | 34 | DirectIOTest 35 | false 36 | false 37 | 38 | jar-with-dependencies 39 | 40 | 41 | 42 | 43 | org.apache.maven 44 | maven-core 45 | 2.2.1 46 | 47 | 48 | 49 | 50 | make-assembly 51 | package 52 | 53 | single 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.sonatype.oss 63 | oss-parent 64 | 7 65 | 66 | 67 | 68 | 69 | The Apache Software License, Version 2.0 70 | http://www.apache.org/licenses/LICENSE-2.0.txt 71 | repo 72 | A business-friendly OSS license 73 | 74 | 75 | 76 | 77 | 78 | kirito 79 | xujingfeng 80 | kirito.moe@foxmail.com 81 | http://www.cnkirito.moe 82 | 83 | Owner 84 | 85 | 86 | https://www.cnkirito.moe/css/images/avatar.png 87 | 88 | 89 | 90 | 91 | 92 | scm:git:https://github.com/lexburner/kdio 93 | scm:git:git@github.com:lexburner/kdio.git 94 | https://github.com/lexburner/kdio 95 | 96 | 97 | 98 | 99 | release 100 | 101 | 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-source-plugin 106 | 2.2.1 107 | 108 | 109 | package 110 | 111 | jar-no-fork 112 | 113 | 114 | 115 | 116 | 117 | 118 | org.apache.maven.plugins 119 | maven-javadoc-plugin 120 | 2.9.1 121 | 122 | 123 | package 124 | 125 | jar 126 | 127 | 128 | 129 | 130 | 131 | 132 | org.apache.maven.plugins 133 | maven-gpg-plugin 134 | 1.6 135 | 136 | 137 | verify 138 | 139 | sign 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | oss 149 | https://oss.sonatype.org/content/repositories/snapshots/ 150 | 151 | 152 | oss 153 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | net.java.dev.jna 162 | jna 163 | 5.2.0 164 | 165 | 166 | org.slf4j 167 | slf4j-api 168 | 1.7.25 169 | 170 | 171 | org.slf4j 172 | slf4j-log4j12 173 | 1.7.25 174 | 175 | 176 | junit 177 | junit 178 | 4.12 179 | test 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectChannel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 xujingfeng (kirito.moe@foxmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | import java.io.IOException; 19 | import java.nio.ByteBuffer; 20 | import java.nio.channels.Channel; 21 | 22 | public interface DirectChannel extends Channel { 23 | /** 24 | * Writes from the src buffer into this channel at position. 25 | * 26 | * @param src 27 | * The {@link ByteBuffer} to write from 28 | * 29 | * @param position 30 | * The position within the file at which to start writing 31 | * 32 | * @return How many bytes were written from src into the file 33 | * @throws IOException 34 | */ 35 | int write(ByteBuffer src, long position) throws IOException; 36 | 37 | /** 38 | * Reads from this channel into the dst buffer from position. 39 | * 40 | * @param dst 41 | * The {@link ByteBuffer} to read into 42 | * 43 | * @param position 44 | * The position within the file at which to start reading 45 | * 46 | * @return How many bytes were placed into dst 47 | * @throws IOException 48 | */ 49 | int read(ByteBuffer dst, long position) throws IOException; 50 | 51 | /** 52 | * @return The file size for this channel 53 | */ 54 | long size(); 55 | 56 | /** 57 | * @return true if this channel is read only, false otherwise 58 | */ 59 | boolean isReadOnly(); 60 | 61 | /** 62 | * Truncates this file's length to fileLength. 63 | * 64 | * @param fileLength The length to which to truncate 65 | * 66 | * @return This UnsafeByteAlignedChannel 67 | * 68 | * @throws IOException 69 | */ 70 | DirectChannel truncate(long fileLength) throws IOException; 71 | 72 | /** 73 | * @return The file descriptor for this channel 74 | */ 75 | int getFD(); 76 | } -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectChannelImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 xujingfeng (kirito.moe@foxmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | import java.nio.ByteBuffer; 21 | import java.nio.channels.ClosedChannelException; 22 | import java.nio.channels.NonWritableChannelException; 23 | 24 | public class DirectChannelImpl implements DirectChannel { 25 | private DirectIOLib lib; 26 | private int fd; 27 | private boolean isOpen; 28 | private long fileLength; 29 | private boolean isReadOnly; 30 | 31 | public static DirectChannel getChannel(File file, boolean readOnly) throws IOException { 32 | DirectIOLib lib = DirectIOLib.getLibForPath(file.toString()); 33 | return getChannel(lib, file, readOnly); 34 | } 35 | 36 | public static DirectChannel getChannel(DirectIOLib lib, File file, boolean readOnly) throws IOException { 37 | int fd = lib.oDirectOpen(file.toString(), readOnly); 38 | long length = file.length(); 39 | return new DirectChannelImpl(lib, fd, length, readOnly); 40 | } 41 | 42 | private DirectChannelImpl(DirectIOLib lib, int fd, long fileLength, boolean readOnly) { 43 | this.lib = lib; 44 | this.fd = fd; 45 | this.isOpen = true; 46 | this.isReadOnly = readOnly; 47 | this.fileLength = fileLength; 48 | } 49 | 50 | private void ensureOpen() throws ClosedChannelException { 51 | if (!isOpen()) { 52 | throw new ClosedChannelException(); 53 | } 54 | } 55 | 56 | private void ensureWritable() { 57 | if (isReadOnly()) { 58 | throw new NonWritableChannelException(); 59 | } 60 | } 61 | 62 | @Override 63 | public int read(ByteBuffer dst, long position) throws IOException { 64 | ensureOpen(); 65 | return lib.pread(fd, dst, position); 66 | } 67 | 68 | @Override 69 | public int write(ByteBuffer src, long position) throws IOException { 70 | ensureOpen(); 71 | ensureWritable(); 72 | assert src.position() == lib.blockStart(src.position()); 73 | 74 | int written = lib.pwrite(fd, src, position); 75 | 76 | // update file length if we wrote past it 77 | fileLength = Math.max(position + written, fileLength); 78 | return written; 79 | } 80 | 81 | @Override 82 | public DirectChannel truncate(final long length) throws IOException { 83 | ensureOpen(); 84 | ensureWritable(); 85 | if (DirectIOLib.ftruncate(fd, length) < 0) { 86 | throw new IOException("Error during truncate on descriptor " + fd + ": " + 87 | DirectIOLib.getLastError()); 88 | } 89 | fileLength = length; 90 | return this; 91 | } 92 | 93 | @Override 94 | public long size() { 95 | return fileLength; 96 | } 97 | 98 | @Override 99 | public int getFD() { 100 | return fd; 101 | } 102 | 103 | 104 | @Override 105 | public boolean isOpen() { 106 | return isOpen; 107 | } 108 | 109 | @Override 110 | public boolean isReadOnly() { 111 | return isReadOnly; 112 | } 113 | 114 | @Override 115 | public void close() throws IOException { 116 | if (!isOpen()) { 117 | return; 118 | } 119 | try { 120 | if (!isReadOnly()) { 121 | truncate(fileLength); 122 | } 123 | } finally { 124 | isOpen = false; 125 | if (lib.close(fd) < 0) { 126 | throw new IOException("Error closing file with descriptor " + fd + ": " + 127 | DirectIOLib.getLastError()); 128 | } 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectIOLib.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Stephen Macke (smacke@cs.stanford.edu) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | import com.sun.jna.Native; 19 | import com.sun.jna.NativeLong; 20 | import com.sun.jna.Platform; 21 | import com.sun.jna.Pointer; 22 | import com.sun.jna.ptr.PointerByReference; 23 | import org.apache.log4j.Logger; 24 | import sun.nio.ch.DirectBuffer; 25 | 26 | import java.io.IOException; 27 | import java.nio.ByteBuffer; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | /** 32 | * Class containing native hooks and utility methods for performing direct I/O, using 33 | * the Linux O_DIRECT flag. 34 | * 35 | * This class is initialized at class load time, by registering JNA hooks into native methods. 36 | * It also calculates Linux kernel version-dependent alignment amount (in bytes) for use with the O_DIRECT flag, 37 | * when given a string for a file or directory. 38 | */ 39 | public class DirectIOLib { 40 | private static final Logger logger = Logger.getLogger(DirectIOLib.class); 41 | public static boolean binit; 42 | 43 | static { 44 | binit = false; 45 | try { 46 | if (!Platform.isLinux()) { 47 | logger.warn("Not running Linux, jaydio support disabled"); 48 | } else { // now check to see if we have O_DIRECT... 49 | 50 | final int linuxVersion = 0; 51 | final int majorRev = 1; 52 | final int minorRev = 2; 53 | 54 | List versionNumbers = new ArrayList(); 55 | for (String v : System.getProperty("os.version").split("\\.|-")) { 56 | if (v.matches("\\d")) { 57 | versionNumbers.add(Integer.parseInt(v)); 58 | } 59 | } 60 | 61 | /* From "man 2 open": 62 | * 63 | * O_DIRECT support was added under Linux in kernel version 2.4.10. Older Linux kernels simply ignore this flag. Some file systems may not implement 64 | * the flag and open() will fail with EINVAL if it is used. 65 | */ 66 | 67 | // test to see whether kernel version >= 2.4.10 68 | if (versionNumbers.get(linuxVersion) > 2) { 69 | binit = true; 70 | } else if (versionNumbers.get(linuxVersion) == 2) { 71 | if (versionNumbers.get(majorRev) > 4) { 72 | binit = true; 73 | } else if (versionNumbers.get(majorRev) == 4 && versionNumbers.get(minorRev) >= 10) { 74 | binit = true; 75 | } 76 | } 77 | 78 | if (binit) { 79 | // get access to open(), pread(), etc 80 | Native.register(Platform.C_LIBRARY_NAME); 81 | } else { 82 | logger.warn(String.format("O_DIRECT not supported on your version of Linux: %d.%d.%d", linuxVersion, majorRev, minorRev)); 83 | } 84 | } 85 | } catch (Throwable e) { 86 | logger.warn("Unable to register libc at class load time: " + e.getMessage(), e); 87 | } 88 | } 89 | 90 | private int fsBlockSize; 91 | private long fsBlockNotMask; 92 | 93 | public DirectIOLib(int fsBlockSize) { 94 | this.fsBlockSize = fsBlockSize; 95 | this.fsBlockNotMask = ~((long)fsBlockSize - 1); 96 | } 97 | 98 | 99 | /** 100 | * Static method to register JNA hooks for doing direct I/O 101 | * 102 | * @param workingDir 103 | * A directory within the mounted file system on which we'll be working 104 | * Should preferably BE the directory in which we'll be working. 105 | */ 106 | public static DirectIOLib getLibForPath(String workingDir) { 107 | int fsBlockSize = initilizeSoftBlockSize(workingDir); 108 | if (fsBlockSize == -1) { 109 | logger.warn("O_DIRECT support non available on your version of Linux (" + System.getProperty("os.version") + "), " + 110 | "please upgrade your kernel in order to use jaydio."); 111 | return null; 112 | } 113 | return new DirectIOLib(fsBlockSize); 114 | } 115 | 116 | /** 117 | * Finds a block size for use with O_DIRECT. Choose it in the most paranoid 118 | * way possible to maximize probability that things work. 119 | * 120 | * @param fileOrDir 121 | * A file or directory within which O_DIRECT access will be performed. 122 | */ 123 | private static int initilizeSoftBlockSize(String fileOrDir) { 124 | 125 | int fsBlockSize = -1; 126 | 127 | if (binit) { 128 | // get file system block size for use with workingDir 129 | // see "man 3 posix_memalign" for why we do this 130 | final int _PC_REC_XFER_ALIGN = 0x11; 131 | 132 | fsBlockSize = pathconf(fileOrDir, _PC_REC_XFER_ALIGN); 133 | /* conservative for version >= 2.6 134 | * "man 2 open": 135 | * 136 | * Under Linux 2.6, alignment 137 | * to 512-byte boundaries suffices. 138 | */ 139 | 140 | // Since O_DIRECT requires pages to be memory aligned with the file system block size, 141 | // we will do this too in case the page size and the block size are different for 142 | // whatever reason. By taking the least common multiple, everything should be happy: 143 | int pageSize = getpagesize(); 144 | fsBlockSize = lcm(fsBlockSize, pageSize); 145 | 146 | // just being completely paranoid: 147 | // (512 is the rule for 2.6+ kernels as mentioned before) 148 | fsBlockSize = lcm(fsBlockSize, 512); 149 | 150 | // lastly, a sanity check 151 | if (fsBlockSize <= 0 || ((fsBlockSize & (fsBlockSize-1)) != 0)) { 152 | logger.warn("file system block size should be a power of two, was found to be " + fsBlockSize); 153 | logger.warn("Disabling O_DIRECT support"); 154 | return -1; 155 | } 156 | } 157 | 158 | return fsBlockSize; 159 | } 160 | 161 | 162 | // -- Java interfaces to native methods 163 | 164 | /** 165 | * Interface into native pread function. Always reads an entire buffer, 166 | * unlike {@link #pwrite(int, ByteBuffer, long) pwrite()} which uses buffer state 167 | * to determine how much of buffer to write. 168 | * 169 | * @param fd 170 | * A file discriptor to pass to native pread 171 | * 172 | * @param buf 173 | * The direct buffer into which to record the file read 174 | * 175 | * @param offset 176 | * The file offset at which to read 177 | * 178 | * @return The number of bytes successfully read from the file 179 | * 180 | * @throws IOException 181 | */ 182 | public int pread(int fd, ByteBuffer buf, long offset) throws IOException { 183 | buf.clear(); // so that we read an entire buffer 184 | final long address = ((DirectBuffer) buf).address(); 185 | Pointer pointer = new Pointer(address); 186 | int n = pread(fd, pointer, new NativeLong(buf.capacity()), new NativeLong(offset)).intValue(); 187 | if (n < 0) { 188 | throw new IOException("error reading file at offset " + offset + ": " + getLastError()); 189 | } 190 | buf.position(n); 191 | return n; 192 | } 193 | 194 | /** 195 | * Interface into native pwrite function. Writes bytes corresponding to the nearest file 196 | * system block boundaries between buf.position() and buf.limit(). 197 | * 198 | * @param fd 199 | * A file descriptor to pass to native pwrite 200 | * 201 | * @param buf 202 | * The direct buffer from which to write 203 | * 204 | * @param offset 205 | * The file offset at which to write 206 | * 207 | * @return The number of bytes successfully written to the file 208 | * 209 | * @throws IOException 210 | */ 211 | public int pwrite(int fd, ByteBuffer buf, long offset) throws IOException { 212 | 213 | // must always write to end of current block 214 | // To handle writes past the logical file size, 215 | // we will later truncate. 216 | final int start = buf.position(); 217 | assert start == blockStart(start); 218 | final int toWrite = blockEnd(buf.limit()) - start; 219 | 220 | final long address = ((DirectBuffer) buf).address(); 221 | Pointer pointer = new Pointer(address); 222 | 223 | int n = pwrite(fd, pointer.share(start), new NativeLong(toWrite), new NativeLong(offset)).intValue(); 224 | if (n < 0) { 225 | throw new IOException("error writing file at offset " + offset + ": " + getLastError()); 226 | } 227 | return n; 228 | } 229 | 230 | /** 231 | * Use the open Linux system call and pass in the O_DIRECT flag. 232 | * Currently the only other flags passed in are O_RDONLY if readOnly 233 | * is true, and (if not) O_RDWR and O_CREAT. 234 | * 235 | * @param pathname 236 | * The path to the file to open. If file does not exist and we are opening 237 | * with readOnly, this will throw an error. Otherwise, if it does 238 | * not exist but we have readOnly set to false, create the file. 239 | * 240 | * @param readOnly 241 | * Whether to pass in O_RDONLY 242 | * 243 | * @return An integer file descriptor for the opened file 244 | * 245 | */ 246 | public int oDirectOpen(String pathname, boolean readOnly) throws IOException { 247 | int flags = OpenFlags.INSTANCE.oDIRECT(); 248 | if (readOnly) { 249 | flags |= OpenFlags.INSTANCE.oRDONLY(); 250 | } else { 251 | flags |= OpenFlags.INSTANCE.oWRONLY() | OpenFlags.INSTANCE.oCREAT(); 252 | } 253 | int fd = open(pathname, flags, 00644); 254 | if (fd < 0) { 255 | throw new IOException("Error opening " + pathname + ", got " + getLastError()); 256 | } 257 | return fd; 258 | } 259 | 260 | /** 261 | * Hooks into errno using Native.getLastError(), and parses it with native strerror function. 262 | * 263 | * @return An error message corresponding to the last errno 264 | */ 265 | public static String getLastError() { 266 | return strerror(Native.getLastError()); 267 | } 268 | 269 | 270 | // -- alignment logic utility methods 271 | 272 | /** 273 | * @return The soft block size for use with transfer multiples 274 | * and memory alignment multiples 275 | */ 276 | public int blockSize() { 277 | return fsBlockSize; 278 | } 279 | 280 | /** 281 | * Returns the default buffer size for file channels doing O_DIRECT 282 | * I/O. By default this is equal to the block size. 283 | * 284 | * @return The default buffer size 285 | */ 286 | public int defaultBufferSize() { 287 | return fsBlockSize; 288 | } 289 | 290 | /** 291 | * Given value, find the largest number less than or equal 292 | * to value which is a multiple of the fs block size. 293 | * 294 | * @param value 295 | * @return The largest number less than or equal to value 296 | * which is a multiple of the soft block size 297 | */ 298 | public long blockStart(long value) { 299 | return value & fsBlockNotMask; 300 | } 301 | 302 | 303 | /** 304 | * @see #blockStart(long) 305 | */ 306 | public int blockStart(int value) { 307 | return (int) (value & fsBlockNotMask); 308 | } 309 | 310 | 311 | /** 312 | * Given value, find the smallest number greater than or equal 313 | * to value which is a multiple of the fs block size. 314 | * 315 | * @param value 316 | * @return The smallest number greater than or equal to value 317 | * which is a multiple of the soft block size 318 | */ 319 | public long blockEnd(long value) { 320 | return (value + fsBlockSize- 1) & fsBlockNotMask; 321 | } 322 | 323 | 324 | 325 | /** 326 | * @see #blockEnd(long) 327 | */ 328 | public int blockEnd(int value) { 329 | return (int) ((value + fsBlockSize - 1) & fsBlockNotMask); 330 | } 331 | 332 | 333 | /** 334 | * Static variant of {@link #blockEnd(int)}. 335 | * @param blockSize 336 | * @param position 337 | * @return The smallest number greater than or equal to position 338 | * which is a multiple of the blockSize 339 | */ 340 | public static long blockEnd(int blockSize, long position) { 341 | long ceil = (position + blockSize - 1)/blockSize; 342 | return ceil*blockSize; 343 | } 344 | 345 | 346 | /** 347 | * Euclid's algo for gcd is more general than we need 348 | * since we only have powers of 2, but w/e 349 | * @param x 350 | * @param y 351 | * @return The least common multiple of x and y 352 | */ 353 | public static int lcm(long x, long y) { 354 | // will hold gcd 355 | long g = x; 356 | long yc = y; 357 | 358 | // get the gcd first 359 | while (yc != 0) { 360 | long t = g; 361 | g = yc; 362 | yc = t % yc; 363 | } 364 | 365 | return (int)(x*y/g); 366 | } 367 | 368 | 369 | /** 370 | * Given a pointer-to-pointer memptr, sets the dereferenced value to point to the start 371 | * of an allocated block of size bytes, where the starting address is a multiple of 372 | * alignment. It is guaranteed that the block may be freed by calling @{link {@link #free(Pointer)} 373 | * on the starting address. See "man 3 posix_memalign". 374 | * 375 | * @param memptr The pointer-to-pointer which will point to the address of the allocated aligned block 376 | * 377 | * @param alignment The alignment multiple of the starting address of the allocated block 378 | * 379 | * @param size The number of bytes to allocate 380 | * 381 | * @return 0 on success, one of the C error codes on failure. 382 | */ 383 | public static native int posix_memalign(PointerByReference memptr, NativeLong alignment, NativeLong size); 384 | 385 | 386 | /** 387 | * See "man 3 free". 388 | * 389 | * @param ptr The pointer to the hunk of memory which needs freeing 390 | */ 391 | public static native void free(Pointer ptr); 392 | 393 | 394 | /** 395 | * See "man 2 close" 396 | * 397 | * @param fd The file descriptor of the file to close 398 | * 399 | * @return 0 on success, -1 on error 400 | */ 401 | public native int close(int fd); // musn't forget to do this 402 | 403 | // -- more native function hooks -- 404 | 405 | public static native int ftruncate(int fd, long length); 406 | 407 | private static native NativeLong pwrite(int fd, Pointer buf, NativeLong count, NativeLong offset); 408 | private static native NativeLong pread(int fd, Pointer buf, NativeLong count, NativeLong offset); 409 | private static native int open(String pathname, int flags); 410 | private static native int open(String pathname, int flags, int mode); 411 | private static native int getpagesize(); 412 | private static native int pathconf(String path, int name); 413 | private static native String strerror(int errnum); 414 | 415 | } 416 | -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectIOTestMain.java: -------------------------------------------------------------------------------- 1 | package moe.cnkirito.kdio; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.ByteBuffer; 6 | 7 | /** 8 | * @author daofeng.xjf 9 | */ 10 | public class DirectIOTestMain { 11 | 12 | public static DirectIOLib directIOLib = DirectIOLib.getLibForPath("/"); 13 | 14 | private static final int BLOCK_SIZE = 4 * 1024; 15 | 16 | public static void main(String[] args) throws IOException { 17 | write(); 18 | read(); 19 | } 20 | 21 | private static void write() throws IOException { 22 | if (DirectIOLib.binit) { 23 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 24 | for (int i = 0; i < BLOCK_SIZE; i++) { 25 | byteBuffer.putInt(i); 26 | } 27 | byteBuffer.flip(); 28 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 29 | directRandomAccessFile.write(byteBuffer, 0); 30 | } else { 31 | throw new RuntimeException("your system do not support direct io"); 32 | } 33 | } 34 | 35 | public static void read() throws IOException { 36 | if (DirectIOLib.binit) { 37 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 38 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 39 | directRandomAccessFile.read(byteBuffer, 0); 40 | byteBuffer.flip(); 41 | for (int i = 0; i < BLOCK_SIZE; i++) { 42 | System.out.print(byteBuffer.getInt() + " "); 43 | } 44 | } else { 45 | throw new RuntimeException("your system do not support direct io"); 46 | } 47 | } 48 | 49 | /** 50 | * 51 | * @param input 52 | * @return 53 | */ 54 | public String test(String input){ 55 | return null; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectIOUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 xujingfeng (kirito.moe@foxmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | import com.sun.jna.NativeLong; 19 | import com.sun.jna.Pointer; 20 | import com.sun.jna.ptr.PointerByReference; 21 | 22 | import java.lang.reflect.Method; 23 | import java.nio.ByteBuffer; 24 | import java.nio.ByteOrder; 25 | 26 | public class DirectIOUtils { 27 | public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder(); 28 | 29 | /** 30 | * Allocate capacity bytes of native memory for use as a buffer, and 31 | * return a {@link ByteBuffer} which gives an interface to this memory. The 32 | * memory is allocated with 33 | * {@link DirectIOLib#posix_memalign(PointerByReference, NativeLong, NativeLong) DirectIOLib#posix_memalign()} 34 | * to ensure that the buffer can be used with O_DIRECT. 35 | ** 36 | * @param capacity The requested number of bytes to allocate 37 | * 38 | * @return A new JnaMemAlignedBuffer of capacity bytes aligned in native memory. 39 | */ 40 | public static ByteBuffer allocateForDirectIO(DirectIOLib lib, int capacity) { 41 | if (capacity % lib.blockSize() > 0) { 42 | throw new IllegalArgumentException("Capacity (" + capacity + ") must be a multiple" 43 | + "of the block size (" + lib.blockSize() + ")"); 44 | } 45 | NativeLong blockSize = new NativeLong(lib.blockSize()); 46 | PointerByReference pointerToPointer = new PointerByReference(); 47 | 48 | // align memory for use with O_DIRECT 49 | DirectIOLib.posix_memalign(pointerToPointer, blockSize, new NativeLong(capacity)); 50 | return wrapPointer(Pointer.nativeValue(pointerToPointer.getValue()), capacity); 51 | } 52 | 53 | /** 54 | * @param ptr Pointer to wrap. 55 | * @param len Memory location length. 56 | * @return Byte buffer wrapping the given memory. 57 | */ 58 | public static ByteBuffer wrapPointer(long ptr, int len) { 59 | try { 60 | ByteBuffer buf = (ByteBuffer)NEW_DIRECT_BUF_MTD.invoke(JAVA_NIO_ACCESS_OBJ, ptr, len, null); 61 | 62 | assert buf.isDirect(); 63 | return buf; 64 | } 65 | catch (ReflectiveOperationException e) { 66 | throw new RuntimeException("JavaNioAccess#newDirectByteBuffer() method is unavailable.", e); 67 | } 68 | } 69 | 70 | /** JavaNioAccess object. */ 71 | private static final Object JAVA_NIO_ACCESS_OBJ = javaNioAccessObject(); 72 | 73 | /** JavaNioAccess#newDirectByteBuffer method. */ 74 | private static final Method NEW_DIRECT_BUF_MTD = newDirectBufferMethod(); 75 | 76 | /** 77 | * Returns reference to {@code JavaNioAccess.newDirectByteBuffer} method 78 | * from private API for corresponding Java version. 79 | * 80 | * @return Reference to {@code JavaNioAccess.newDirectByteBuffer} method 81 | * @throws RuntimeException If getting access to the private API is failed. 82 | */ 83 | private static Method newDirectBufferMethod() { 84 | 85 | try { 86 | Class cls = JAVA_NIO_ACCESS_OBJ.getClass(); 87 | 88 | Method mtd = cls.getMethod("newDirectByteBuffer", long.class, int.class, Object.class); 89 | 90 | mtd.setAccessible(true); 91 | 92 | return mtd; 93 | } 94 | catch (ReflectiveOperationException e) { 95 | throw new RuntimeException(miscPackage() + ".JavaNioAccess#newDirectByteBuffer() method is unavailable.", e); 96 | } 97 | } 98 | 99 | /** 100 | * Returns {@code JavaNioAccess} instance from private API for corresponding Java version. 101 | * 102 | * @return {@code JavaNioAccess} instance for corresponding Java version. 103 | * @throws RuntimeException If getting access to the private API is failed. 104 | */ 105 | private static Object javaNioAccessObject() { 106 | String pkgName = miscPackage(); 107 | 108 | try { 109 | Class cls = Class.forName(pkgName + ".misc.SharedSecrets"); 110 | 111 | Method mth = cls.getMethod("getJavaNioAccess"); 112 | 113 | return mth.invoke(null); 114 | } 115 | catch (ReflectiveOperationException e) { 116 | throw new RuntimeException(pkgName + ".misc.JavaNioAccess class is unavailable.", e); 117 | } 118 | } 119 | 120 | private static String miscPackage() { 121 | // Need return 'jdk.interna' if current Java version >= 9 122 | return "sun"; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/DirectRandomAccessFile.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Stephen Macke (smacke@cs.stanford.edu) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | import java.io.Closeable; 19 | import java.io.File; 20 | import java.io.FileNotFoundException; 21 | import java.io.IOException; 22 | import java.io.RandomAccessFile; 23 | import java.nio.ByteBuffer; 24 | 25 | /** 26 | * Class to emulate the behavior of {@link RandomAccessFile}, but using direct I/O. 27 | * 28 | */ 29 | public class DirectRandomAccessFile implements Closeable { 30 | 31 | private DirectChannel channel; 32 | 33 | 34 | /** 35 | * @param file The file to open 36 | * 37 | * @param mode Either "rw" or "r", depending on whether this file is read only 38 | * 39 | * @throws IOException 40 | */ 41 | public DirectRandomAccessFile(File file, String mode) 42 | throws IOException { 43 | 44 | boolean readOnly = false; 45 | if (mode.equals("r")) { 46 | readOnly = true; 47 | } else if (!mode.equals("rw")) { 48 | throw new IllegalArgumentException("only r and rw modes supported"); 49 | } 50 | 51 | if (readOnly && !file.isFile()) { 52 | throw new FileNotFoundException("couldn't find file " + file); 53 | } 54 | 55 | this.channel = DirectChannelImpl.getChannel(file, readOnly); 56 | } 57 | 58 | @Override 59 | public void close() throws IOException { 60 | channel.close(); 61 | } 62 | 63 | 64 | public int write(ByteBuffer src, long position) throws IOException { 65 | return channel.write(src, position); 66 | } 67 | 68 | public int read(ByteBuffer dst, long position) throws IOException { 69 | return channel.read(dst, position); 70 | } 71 | 72 | /** 73 | * @return The current position in the file 74 | */ 75 | public long getFilePointer() { 76 | return channel.getFD(); 77 | } 78 | 79 | /** 80 | * @return The current length of the file 81 | */ 82 | public long length() { 83 | return channel.size(); 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/moe/cnkirito/kdio/OpenFlags.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014 Stephen Macke (smacke@cs.stanford.edu) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package moe.cnkirito.kdio; 17 | 18 | /** 19 | * Constants for {@link DirectIOLib#oDirectOpen(String, boolean)}. 20 | */ 21 | public interface OpenFlags { 22 | OpenFlags INSTANCE = instance(); 23 | 24 | static OpenFlags instance() { 25 | String arch = System.getProperty("os.arch"); 26 | switch (arch) { 27 | case "aarch64": 28 | return new Aarch64OpenFlags(); 29 | default: 30 | return new DefaultOpenFlags(); 31 | } 32 | } 33 | 34 | default int oRDONLY() { 35 | return 00; 36 | } 37 | default int oWRONLY() { 38 | return 01; 39 | } 40 | default int oRDWR() { 41 | return 02; 42 | } 43 | default int oCREAT() { 44 | return 0100; 45 | } 46 | default int oTRUNC() { 47 | return 01000; 48 | } 49 | default int oDIRECT() { 50 | return 040000; 51 | } 52 | default int oSYNC() { 53 | return 04010000; 54 | } 55 | 56 | class DefaultOpenFlags implements OpenFlags { 57 | } 58 | 59 | class Aarch64OpenFlags implements OpenFlags { 60 | @Override 61 | public int oDIRECT() { 62 | return 0200000; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/moe/cnkirito/kdio/DirectIOTest.java: -------------------------------------------------------------------------------- 1 | package moe.cnkirito.kdio; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.ByteBuffer; 8 | 9 | /** 10 | * @author daofeng.xjf 11 | */ 12 | public class DirectIOTest { 13 | 14 | public static DirectIOLib directIOLib = DirectIOLib.getLibForPath("/"); 15 | 16 | private static final int BLOCK_SIZE = 4 * 1024; 17 | 18 | @Test 19 | public void writeTest() throws IOException { 20 | if (DirectIOLib.binit) { 21 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 22 | for (int i = 0; i < BLOCK_SIZE; i++) { 23 | byteBuffer.putInt(i); 24 | } 25 | byteBuffer.flip(); 26 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 27 | directRandomAccessFile.write(byteBuffer, 0); 28 | } else { 29 | throw new RuntimeException("your system do not support direct io"); 30 | } 31 | } 32 | 33 | @Test 34 | public void readTest() throws IOException { 35 | if (DirectIOLib.binit) { 36 | ByteBuffer byteBuffer = DirectIOUtils.allocateForDirectIO(directIOLib, 4 * BLOCK_SIZE); 37 | DirectRandomAccessFile directRandomAccessFile = new DirectRandomAccessFile(new File("./database.data"), "rw"); 38 | directRandomAccessFile.read(byteBuffer, 0); 39 | byteBuffer.flip(); 40 | for (int i = 0; i < BLOCK_SIZE; i++) { 41 | System.out.print(byteBuffer.getInt() + " "); 42 | } 43 | } else { 44 | throw new RuntimeException("your system do not support direct io"); 45 | } 46 | } 47 | 48 | } 49 | --------------------------------------------------------------------------------