Update LimboDB.java to load libraries from /lib

This commit is contained in:
김선우 2025-02-02 12:35:34 +09:00
parent 6168ad2f6e
commit 80adeb520a

View file

@ -2,6 +2,10 @@ package org.github.tursodatabase.core;
import static org.github.tursodatabase.utils.ByteArrayUtils.stringToUtf8ByteArray;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.concurrent.locks.ReentrantLock;
import org.github.tursodatabase.LimboErrorCode;
@ -30,17 +34,136 @@ public final class LimboDB extends AbstractDB {
}
}
/** Loads the SQLite interface backend. */
/**
* Enum representing different architectures and their corresponding library paths and file
* extensions.
*/
enum Architecture {
MACOS_ARM64("libs/macos_arm64/lib_limbo_java.dylib", ".dylib"),
MACOS_X86("libs/macos_x86/lib_limbo_java.dylib", ".dylib"),
WINDOWS("libs/windows/lib_limbo_java.dll", ".dll"),
UNSUPPORTED("", "");
private final String libPath;
private final String fileExtension;
Architecture(String libPath, String fileExtension) {
this.libPath = libPath;
this.fileExtension = fileExtension;
}
public String getLibPath() {
return libPath;
}
public String getFileExtension() {
return fileExtension;
}
public static Architecture detect() {
String osName = System.getProperty("os.name").toLowerCase();
String osArch = System.getProperty("os.arch").toLowerCase();
if (osName.contains("mac")) {
if (osArch.contains("aarch64") || osArch.contains("arm64")) {
return MACOS_ARM64;
} else if (osArch.contains("x86_64") || osArch.contains("amd64")) {
return MACOS_X86;
}
} else if (osName.contains("win")) {
return WINDOWS;
}
return UNSUPPORTED;
}
}
/**
* This method attempts to load the native library required for Limbo operations. It first tries
* to load the library from the system's library path using {@link #defaultLoad()}. If that fails,
* it attempts to load the library from the JAR file using {@link #loadFromJar()}. If either
* method succeeds, the `isLoaded` flag is set to true. If both methods fail, an {@link
* InternalError} is thrown indicating that the necessary native library could not be loaded.
*
* @throws InternalError if the native library cannot be loaded from either the system path or the
* JAR file.
*/
public static void load() {
if (isLoaded) {
return;
}
if (defaultLoad() || loadFromJar()) {
isLoaded = true;
return;
}
throw new InternalError("Unable to load necessary native library");
}
/**
* Load the native library from the system path.
*
* <p>This method attempts to load the native library named "_limbo_java" from the system's
* library path. If the library is successfully loaded, the `isLoaded` flag is set to true.
*
* @return true if the library was successfully loaded, false otherwise.
*/
private static boolean defaultLoad() {
try {
System.loadLibrary("_limbo_java");
} finally {
isLoaded = true;
return true;
} catch (Throwable t) {
logger.info("Unable to load from default path: {}", String.valueOf(t));
}
return false;
}
/**
* Load the native library from the JAR file.
*
* <p>By default, native libraries are packaged within the JAR file. This method extracts the
* appropriate native library for the current operating system and architecture from the JAR and
* loads it.
*
* @return true if the library was successfully loaded, false otherwise.
*/
private static boolean loadFromJar() {
Architecture arch = Architecture.detect();
if (arch == Architecture.UNSUPPORTED) {
logger.info("Unsupported OS or architecture");
return false;
}
try {
InputStream is = LimboDB.class.getClassLoader().getResourceAsStream(arch.getLibPath());
assert is != null;
File file = convertInputStreamToFile(is, arch);
System.load(file.getPath());
return true;
} catch (Throwable t) {
logger.info("Unable to load from jar: {}", String.valueOf(t));
}
return false;
}
private static File convertInputStreamToFile(InputStream is, Architecture arch)
throws IOException {
File tempFile = File.createTempFile("lib", arch.getFileExtension());
tempFile.deleteOnExit();
try (FileOutputStream os = new FileOutputStream(tempFile)) {
int read;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
}
return tempFile;
}
/**