]>
Commit | Line | Data |
---|---|---|
f67539c2 | 1 | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. |
7c673cae FG |
2 | package org.rocksdb; |
3 | ||
4 | import java.io.*; | |
5 | import java.nio.file.Files; | |
6 | import java.nio.file.StandardCopyOption; | |
7 | ||
8 | import org.rocksdb.util.Environment; | |
9 | ||
10 | /** | |
11 | * This class is used to load the RocksDB shared library from within the jar. | |
12 | * The shared library is extracted to a temp folder and loaded from there. | |
13 | */ | |
14 | public class NativeLibraryLoader { | |
15 | //singleton | |
16 | private static final NativeLibraryLoader instance = new NativeLibraryLoader(); | |
17 | private static boolean initialized = false; | |
18 | ||
19 | private static final String sharedLibraryName = Environment.getSharedLibraryName("rocksdb"); | |
20 | private static final String jniLibraryName = Environment.getJniLibraryName("rocksdb"); | |
1e59de90 TL |
21 | private static final /* @Nullable */ String fallbackJniLibraryName = |
22 | Environment.getFallbackJniLibraryName("rocksdb"); | |
7c673cae | 23 | private static final String jniLibraryFileName = Environment.getJniLibraryFileName("rocksdb"); |
1e59de90 TL |
24 | private static final /* @Nullable */ String fallbackJniLibraryFileName = |
25 | Environment.getFallbackJniLibraryFileName("rocksdb"); | |
7c673cae FG |
26 | private static final String tempFilePrefix = "librocksdbjni"; |
27 | private static final String tempFileSuffix = Environment.getJniLibraryExtension(); | |
28 | ||
29 | /** | |
30 | * Get a reference to the NativeLibraryLoader | |
31 | * | |
32 | * @return The NativeLibraryLoader | |
33 | */ | |
34 | public static NativeLibraryLoader getInstance() { | |
35 | return instance; | |
36 | } | |
37 | ||
38 | /** | |
39 | * Firstly attempts to load the library from <i>java.library.path</i>, | |
40 | * if that fails then it falls back to extracting | |
41 | * the library from the classpath | |
42 | * {@link org.rocksdb.NativeLibraryLoader#loadLibraryFromJar(java.lang.String)} | |
43 | * | |
44 | * @param tmpDir A temporary directory to use | |
45 | * to copy the native library to when loading from the classpath. | |
46 | * If null, or the empty string, we rely on Java's | |
47 | * {@link java.io.File#createTempFile(String, String)} | |
48 | * function to provide a temporary location. | |
49 | * The temporary file will be registered for deletion | |
50 | * on exit. | |
51 | * | |
52 | * @throws java.io.IOException if a filesystem operation fails. | |
53 | */ | |
54 | public synchronized void loadLibrary(final String tmpDir) throws IOException { | |
55 | try { | |
1e59de90 TL |
56 | // try dynamic library |
57 | System.loadLibrary(sharedLibraryName); | |
58 | return; | |
59 | } catch (final UnsatisfiedLinkError ule) { | |
60 | // ignore - try from static library | |
61 | } | |
62 | ||
63 | try { | |
64 | // try static library | |
65 | System.loadLibrary(jniLibraryName); | |
66 | return; | |
67 | } catch (final UnsatisfiedLinkError ule) { | |
68 | // ignore - then try static library fallback or from jar | |
69 | } | |
70 | ||
71 | if (fallbackJniLibraryName != null) { | |
7c673cae | 72 | try { |
1e59de90 TL |
73 | // try static library fallback |
74 | System.loadLibrary(fallbackJniLibraryName); | |
75 | return; | |
76 | } catch (final UnsatisfiedLinkError ule) { | |
77 | // ignore - then try from jar | |
7c673cae FG |
78 | } |
79 | } | |
1e59de90 TL |
80 | |
81 | // try jar | |
82 | loadLibraryFromJar(tmpDir); | |
7c673cae FG |
83 | } |
84 | ||
85 | /** | |
86 | * Attempts to extract the native RocksDB library | |
87 | * from the classpath and load it | |
88 | * | |
89 | * @param tmpDir A temporary directory to use | |
90 | * to copy the native library to. If null, | |
91 | * or the empty string, we rely on Java's | |
92 | * {@link java.io.File#createTempFile(String, String)} | |
93 | * function to provide a temporary location. | |
94 | * The temporary file will be registered for deletion | |
95 | * on exit. | |
96 | * | |
97 | * @throws java.io.IOException if a filesystem operation fails. | |
98 | */ | |
99 | void loadLibraryFromJar(final String tmpDir) | |
100 | throws IOException { | |
101 | if (!initialized) { | |
102 | System.load(loadLibraryFromJarToTemp(tmpDir).getAbsolutePath()); | |
103 | initialized = true; | |
104 | } | |
105 | } | |
106 | ||
107 | File loadLibraryFromJarToTemp(final String tmpDir) | |
108 | throws IOException { | |
1e59de90 TL |
109 | InputStream is = null; |
110 | try { | |
111 | // attempt to look up the static library in the jar file | |
112 | String libraryFileName = jniLibraryFileName; | |
113 | is = getClass().getClassLoader().getResourceAsStream(libraryFileName); | |
114 | ||
115 | if (is == null) { | |
116 | // is there a fallback we can try | |
117 | if (fallbackJniLibraryFileName == null) { | |
118 | throw new RuntimeException(libraryFileName + " was not found inside JAR."); | |
119 | } | |
120 | ||
121 | // attempt to look up the fallback static library in the jar file | |
122 | libraryFileName = fallbackJniLibraryFileName; | |
123 | is = getClass().getClassLoader().getResourceAsStream(libraryFileName); | |
124 | if (is == null) { | |
125 | throw new RuntimeException(libraryFileName + " was not found inside JAR."); | |
126 | } | |
20effc67 | 127 | } |
1e59de90 TL |
128 | |
129 | // create a temporary file to copy the library to | |
130 | final File temp; | |
131 | if (tmpDir == null || tmpDir.isEmpty()) { | |
132 | temp = File.createTempFile(tempFilePrefix, tempFileSuffix); | |
133 | } else { | |
134 | final File parentDir = new File(tmpDir); | |
135 | if (!parentDir.exists()) { | |
136 | throw new RuntimeException( | |
137 | "Directory: " + parentDir.getAbsolutePath() + " does not exist!"); | |
138 | } | |
139 | temp = new File(parentDir, libraryFileName); | |
140 | if (temp.exists() && !temp.delete()) { | |
141 | throw new RuntimeException( | |
142 | "File: " + temp.getAbsolutePath() + " already exists and cannot be removed."); | |
143 | } | |
144 | if (!temp.createNewFile()) { | |
145 | throw new RuntimeException("File: " + temp.getAbsolutePath() + " could not be created."); | |
146 | } | |
7c673cae | 147 | } |
1e59de90 TL |
148 | if (!temp.exists()) { |
149 | throw new RuntimeException("File " + temp.getAbsolutePath() + " does not exist."); | |
150 | } else { | |
151 | temp.deleteOnExit(); | |
7c673cae | 152 | } |
7c673cae | 153 | |
1e59de90 TL |
154 | // copy the library from the Jar file to the temp destination |
155 | Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); | |
7c673cae | 156 | |
1e59de90 TL |
157 | // return the temporary library file |
158 | return temp; | |
159 | ||
160 | } finally { | |
161 | if (is != null) { | |
162 | is.close(); | |
7c673cae FG |
163 | } |
164 | } | |
7c673cae FG |
165 | } |
166 | ||
167 | /** | |
168 | * Private constructor to disallow instantiation | |
169 | */ | |
170 | private NativeLibraryLoader() { | |
171 | } | |
172 | } |