Skip to content

Commit

Permalink
fixup! Port workerd to Windows using clang
Browse files Browse the repository at this point in the history
Use SQLite system default VFS on Windows
  • Loading branch information
mrbbot committed Mar 30, 2023
1 parent b40cfdf commit 2f4c551
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
6 changes: 0 additions & 6 deletions src/workerd/util/sqlite-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -181,16 +181,10 @@ KJ_TEST("SQLite backed by real disk") {

{
auto files = dir->listNames();
#if _WIN32
KJ_ASSERT(files.size() == 2);
KJ_EXPECT(files[0] == "foo");
KJ_EXPECT(files[1] == "foo-wal");
#else
KJ_ASSERT(files.size() == 3);
KJ_EXPECT(files[0] == "foo");
KJ_EXPECT(files[1] == "foo-shm");
KJ_EXPECT(files[2] == "foo-wal");
#endif
}
}

Expand Down
58 changes: 53 additions & 5 deletions src/workerd/util/sqlite.c++
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
#include "sqlite.h"
#include <kj/debug.h>

#if !_WIN32
#if _WIN32
#include <kj/win32-api-version.h>
#include <windows.h>
#include <kj/windows-sanity.h>
#else
#include <unistd.h>
#endif

Expand Down Expand Up @@ -66,13 +70,38 @@ kj::Own<T> ownSqlite(T* obj) {
return kj::Own<T>(obj, disposer);
}

#if _WIN32
// https://github.com/capnproto/capnproto/blob/master/c%2B%2B/src/kj/filesystem-disk-win32.c%2B%2B#L255-L269
static kj::Path getPathFromWin32Handle(HANDLE handle) {
DWORD tryLen = MAX_PATH;
for (;;) {
auto temp = kj::heapArray<wchar_t>(tryLen + 1);
DWORD len = GetFinalPathNameByHandleW(handle, temp.begin(), tryLen, 0);
if (len == 0) {
KJ_FAIL_WIN32("GetFinalPathNameByHandleW", GetLastError());
}
if (len < temp.size()) {
return kj::Path::parseWin32Api(temp.slice(0, len));
}
// Try again with new length.
tryLen = len;
}
}
#endif

} // namespace

// =======================================================================================

SqliteDatabase::SqliteDatabase(const Vfs& vfs, kj::PathPtr path) {
SQLITE_CALL_NODB(sqlite3_open_v2(path.toString().cStr(), &db,
SQLITE_OPEN_READONLY, vfs.getName().cStr()));
KJ_IF_MAYBE(rootedPath, vfs.tryAppend(path)) {
// If we can get the path rooted in the VFS's directory, use the system's default VFS instead
SQLITE_CALL_NODB(sqlite3_open_v2(rootedPath->toString().cStr(), &db,
SQLITE_OPEN_READONLY, nullptr));
} else {
SQLITE_CALL_NODB(sqlite3_open_v2(path.toString().cStr(), &db,
SQLITE_OPEN_READONLY, vfs.getName().cStr()));
}
}

SqliteDatabase::SqliteDatabase(const Vfs& vfs, kj::PathPtr path, kj::WriteMode mode) {
Expand All @@ -88,8 +117,14 @@ SqliteDatabase::SqliteDatabase(const Vfs& vfs, kj::PathPtr path, kj::WriteMode m
}
KJ_REQUIRE(kj::has(mode, kj::WriteMode::MODIFY), "SQLite doesn't support create-exclusive mode");

SQLITE_CALL_NODB(sqlite3_open_v2(path.toString().cStr(), &db,
flags, vfs.getName().cStr()));
KJ_IF_MAYBE(rootedPath, vfs.tryAppend(path)) {
// If we can get the path rooted in the VFS's directory, use the system's default VFS instead
SQLITE_CALL_NODB(sqlite3_open_v2(rootedPath->toString().cStr(), &db,
flags, nullptr));
} else {
SQLITE_CALL_NODB(sqlite3_open_v2(path.toString().cStr(), &db,
flags, vfs.getName().cStr()));
}
}

SqliteDatabase::~SqliteDatabase() noexcept(false) {
Expand Down Expand Up @@ -1197,6 +1232,19 @@ kj::String SqliteDatabase::Vfs::makeName() {
return kj::str("kj-", this);
}

#if _WIN32
kj::Maybe<kj::Path> SqliteDatabase::Vfs::tryAppend(kj::PathPtr suffix) const {
auto handle = KJ_UNWRAP_OR_RETURN(directory.getWin32Handle(), nullptr);
auto root = getPathFromWin32Handle(handle);
return root.append(suffix);
}
#else
kj::Maybe<kj::Path> SqliteDatabase::Vfs::tryAppend(kj::PathPtr suffix) const {
// TODO(someday): consider implementing this on other platforms
return nullptr;
}
#endif

// =======================================================================================

} // namespace workerd
8 changes: 8 additions & 0 deletions src/workerd/util/sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ class SqliteDatabase::Vfs {
// Create the value returned by `getName()`. Called once at construction time and cached in
// `name`.

kj::Maybe<kj::Path> tryAppend(kj::PathPtr suffix) const;
// Tries to create a new path by appending the given path to this VFS's root directory path.
// This allows us to use the system's default VFS implementation, without wrapping, by passing
// the result of this function to sqlite3_open_v2().
//
// Unfortunately, this requires getting a file path from a kj::Directory. On Windows, we can use
// the GetFinalPathNameByHandleW() API. On Unix, there's no portable way to do this.

friend class SqliteDatabase;
class DefaultLockManager;
};
Expand Down

0 comments on commit 2f4c551

Please sign in to comment.