Skip to content

Commit

Permalink
Set temporary directory in a cross-platfrom way
Browse files Browse the repository at this point in the history
  • Loading branch information
Qiuwen-chen committed Jun 8, 2023
1 parent 7e31ea5 commit 5cb84c5
Show file tree
Hide file tree
Showing 17 changed files with 119 additions and 49 deletions.
5 changes: 5 additions & 0 deletions src/bridge/cppbridge/CoreBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,8 @@ void WCDBCorePurgeAllDatabase(void)
{
WCDB::Core::shared().purgeDatabasePool();
}

bool WCDBCoreSetDefaultTemporaryDirectory(const char* _Nullable dir)
{
return WCDB::Core::shared().setDefaultTemporaryDirectory(dir);
}
1 change: 1 addition & 0 deletions src/bridge/cppbridge/CoreBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ WCDB_EXTERN_C_BEGIN
CPPDatabase WCDBCoreCreateDatabase(const char* _Nonnull path);
void WCDBCoreSetDefaultCipherConfig(int version);
void WCDBCorePurgeAllDatabase(void);
bool WCDBCoreSetDefaultTemporaryDirectory(const char* _Nullable dir);

WCDB_EXTERN_C_END
6 changes: 6 additions & 0 deletions src/common/base/FileManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,12 @@ bool FileManager::moveItems(const std::list<std::pair<StringView, StringView>> &

bool FileManager::createDirectoryWithIntermediateDirectories(const UnsafeStringView &directory)
{
if (directory.length() == 0) {
Error error(Error::Code::IOError, Error::Level::Error, "empty directory");
Notifier::shared().notify(error);
SharedThreadedErrorProne::setThreadedError(std::move(error));
return false;
}
auto exists = directoryExists(directory);
if (!exists.succeed()) {
return false;
Expand Down
6 changes: 5 additions & 1 deletion src/common/base/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ StringView getDirectoryName(const UnsafeStringView &base)
{
std::string dir = base.data();
int64_t found = dir.find_last_of(kPathSeparator);
return StringView(dir.substr(0, found));
if (found >= 0) {
return StringView(dir.substr(0, found));
} else {
return StringView();
}
}

StringView normalize(const UnsafeStringView &path)
Expand Down
2 changes: 2 additions & 0 deletions src/common/base/SQLite.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
extern "C" {
#endif

extern char *sqlite3_temp_directory;

int sqlcipher_set_default_hmac_algorithm(int algorithm);
int sqlcipher_set_default_kdf_algorithm(int algorithm);
void sqlcipher_set_default_kdf_iter(int iter);
Expand Down
19 changes: 19 additions & 0 deletions src/common/base/StringView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,25 @@ StringView StringView::makeConstant(const char* string)
return ret;
}

StringView StringView::createConstant(const char* string)
{
StringView ret;
if (string != nullptr) {
size_t length = strlen(string);
char* data = (char*) malloc((length + 1) * sizeof(char));
if (data != nullptr) {
memcpy((void*) data, (void*) string, length);
data[length] = '\0';
} else {
length = 0;
}
ret.m_data = data;
ret.m_length = length;
ret.m_referenceCount = (std::atomic<int>*) ConstanceReference;
}
return ret;
}

bool StringViewComparator::operator()(const StringView& lhs, const StringView& rhs) const
{
return lhs.compare(rhs) < 0;
Expand Down
1 change: 1 addition & 0 deletions src/common/base/StringView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class StringView final : public UnsafeStringView {
static StringView formatted(const char* format, ...);
static StringView hexString(const UnsafeData& data);
static StringView makeConstant(const char* string);
static StringView createConstant(const char* string);

protected:
void assignString(const char* content, size_t length);
Expand Down
17 changes: 14 additions & 3 deletions src/common/core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,19 +404,19 @@ void Core::setNotificationWhenErrorTraced(const UnsafeStringView& path,
}

#pragma mark - Config
void Core::setABTestConfig(const UnsafeStringView configName, const UnsafeStringView configValue)
void Core::setABTestConfig(const UnsafeStringView& configName, const UnsafeStringView& configValue)
{
LockGuard memoryGuard(m_memory);
m_abtestConfig[configName] = configValue;
}

void Core::removeABTestConfig(const UnsafeStringView configName)
void Core::removeABTestConfig(const UnsafeStringView& configName)
{
LockGuard memoryGuard(m_memory);
m_abtestConfig.erase(configName);
}

Optional<UnsafeStringView> Core::getABTestConfig(UnsafeStringView configName)
Optional<UnsafeStringView> Core::getABTestConfig(const UnsafeStringView& configName)
{
SharedLockGuard memoryGuard(m_memory);
if (m_abtestConfig.find(configName) != m_abtestConfig.end()) {
Expand Down Expand Up @@ -458,4 +458,15 @@ void Core::setDefaultCipherConfiguration(int version)
}
}

bool Core::setDefaultTemporaryDirectory(const UnsafeStringView& dir)
{
if (dir.length() > 0) {
if (!FileManager::createDirectoryWithIntermediateDirectories(dir)) {
return false;
}
}
sqlite3_temp_directory = (char*) StringView::createConstant(dir.data()).data();
return true;
}

} // namespace WCDB
8 changes: 5 additions & 3 deletions src/common/core/Core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,13 @@ class Core final : public DatabasePoolEvent, public OperationEvent {

#pragma mark - Config
public:
void setABTestConfig(const UnsafeStringView configName, const UnsafeStringView configValue);
void removeABTestConfig(const UnsafeStringView configName);
Optional<UnsafeStringView> getABTestConfig(UnsafeStringView configName);
void setABTestConfig(const UnsafeStringView& configName,
const UnsafeStringView& configValue);
void removeABTestConfig(const UnsafeStringView& configName);
Optional<UnsafeStringView> getABTestConfig(const UnsafeStringView& configName);

void setDefaultCipherConfiguration(int version);
bool setDefaultTemporaryDirectory(const UnsafeStringView& dir);

protected:
Configs m_configs;
Expand Down
4 changes: 2 additions & 2 deletions src/cpp/core/Database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,9 @@ void Database::removeConfig(const UnsafeStringView& name)
m_innerDatabase->removeConfig(name);
}

void Database::setDefaultTemporaryDirectory(UnsafeStringView dir)
bool Database::setDefaultTemporaryDirectory(const UnsafeStringView& directory)
{
setenv("SQLITE_TMPDIR", dir.data(), 1);
return Core::shared().setDefaultTemporaryDirectory(directory);
}

void Database::filterMigration(MigrationFilter filter)
Expand Down
4 changes: 3 additions & 1 deletion src/cpp/core/Database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,10 @@ class Database final : public HandleORMOperation {
4. /tmp;
5. The current working directory (".")
Please see: https://www.sqlite.org/tempfiles.html
@param directory a global temporary directory.
@return true if directory exists or create directory success.
*/
static void setDefaultTemporaryDirectory(UnsafeStringView dir);
static bool setDefaultTemporaryDirectory(const UnsafeStringView &directory);

#pragma mark - Migration
typedef struct MigrationInfo {
Expand Down
15 changes: 15 additions & 0 deletions src/cpp/tests/interface/CPPConfigTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,19 @@ - (void)test_cipher_with_diferent_version
TestCaseAssertTrue(self.database->canOpen());
}

- (void)testSetTemporaryDirectory
{
TestCaseAssertFalse(WCDB::Database::setDefaultTemporaryDirectory("wrongDir"));

NSString* tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"dbTempDir"];
TestCaseAssertTrue(WCDB::Database::setDefaultTemporaryDirectory(tempDir.UTF8String));
WCDB::StatementPragma getDirStatement = WCDB::StatementPragma().pragma(WCDB::Pragma("temp_store_directory"));
WCDB::OptionalValue dir = self.database->getValueFromStatement(getDirStatement);
TestCaseAssertTrue(dir.hasValue() && dir.value().textValue().compare(tempDir.UTF8String) == 0);

TestCaseAssertTrue(WCDB::Database::setDefaultTemporaryDirectory(NULL));
dir = self.database->getValueFromStatement(getDirStatement);
TestCaseAssertTrue(dir.hasValue() && dir.value().textValue().length() == 0);
}

@end
4 changes: 3 additions & 1 deletion src/objc/database/WCTDatabase+File.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ NS_ASSUME_NONNULL_BEGIN
4. /tmp;
5. The current working directory (".")
Please see: https://www.sqlite.org/tempfiles.html
@param directory a global temporary directory.
@return YES if directory exists or create directory success.
*/
+ (BOOL)setDefaultTemporaryDatabaseFileDirectory:(NSString *)dir;
+ (BOOL)setDefaultTemporaryDatabaseFileDirectory:(NSString *_Nullable)directory;

@end

Expand Down
38 changes: 2 additions & 36 deletions src/objc/database/WCTDatabase+File.mm
Original file line number Diff line number Diff line change
Expand Up @@ -53,43 +53,9 @@ - (WCTOptionalSize)getFilesSize
return _database->getFilesSize();
}

+ (BOOL)setDefaultTemporaryDatabaseFileDirectory:(NSString *)dir
+ (BOOL)setDefaultTemporaryDatabaseFileDirectory:(NSString *_Nullable)directory
{
if (dir.length == 0) {
WCDB::Error error(WCDB::Error::Code::Error,
WCDB::Error::Level::Error,
"Set nil temporary database files directory!");
WCDB::Notifier::shared().notify(error);
return NO;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = FALSE;
BOOL isDirExist = [fileManager fileExistsAtPath:dir
isDirectory:&isDir];
if (!isDirExist) {
BOOL bCreateDir = [fileManager createDirectoryAtPath:dir
withIntermediateDirectories:YES
attributes:nil
error:nil];
if (!bCreateDir) {
WCDB::Error error(WCDB::Error::Code::Error,
WCDB::Error::Level::Error,
"Fail to create temporary database files directory");
error.infos.insert_or_assign("Path", dir.UTF8String);
WCDB::Notifier::shared().notify(error);
return NO;
}
} else if (!isDir) {
WCDB::Error error(WCDB::Error::Code::Error,
WCDB::Error::Level::Error,
"Invalid directory");
error.infos.insert_or_assign("Path", dir.UTF8String);
WCDB::Notifier::shared().notify(error);
return NO;
}

setenv("SQLITE_TMPDIR", dir.UTF8String, 1);
return YES;
return WCDB::Core::shared().setDefaultTemporaryDirectory(directory);
}

@end
17 changes: 17 additions & 0 deletions src/objc/tests/config/ConfigTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,21 @@ - (void)test_abtest_config
}];
}

- (void)testSetTemporaryDirectory
{
NSString* wrongDir = @"wrongDir";
TestCaseAssertFalse([WCTDatabase setDefaultTemporaryDatabaseFileDirectory:wrongDir]);

NSString* tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"dbTempDir"];
TestCaseAssertTrue([WCTDatabase setDefaultTemporaryDatabaseFileDirectory:tempDir]);

WCDB::StatementPragma getDirStatement = WCDB::StatementPragma().pragma(WCDB::Pragma("temp_store_directory"));
WCTValue* dir = [self.database getValueFromStatement:getDirStatement];
TestCaseAssertTrue(dir != nil && [dir.stringValue isEqualToString:tempDir]);

TestCaseAssertTrue([WCTDatabase setDefaultTemporaryDatabaseFileDirectory:nil]);
dir = [self.database getValueFromStatement:getDirStatement];
TestCaseAssertTrue(dir != nil && [dir.stringValue isEqualToString:@""]);
}

@end
6 changes: 4 additions & 2 deletions src/swift/core/base/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,10 @@ public extension Database {
/// 4. /tmp;
/// 5. The current working directory (".")
/// Please see: https://www.sqlite.org/tempfiles.html
static func setDefaultTemporaryDirectory(_ dir: String) {
setenv("SQLITE_TMPDIR".cString, dir.cString, 1)
/// - Parameter directory a global temporary directory.
/// - Returns: true if directory exists or create directory success.
static func setDefaultTemporaryDirectory(_ directory: String) -> Bool {
return WCDBCoreSetDefaultTemporaryDirectory(directory.cString)
}

typealias PerformanceTracer = (String, UInt64, String, Double) -> Void // Path, handleIdentifier, SQL, cost
Expand Down
15 changes: 15 additions & 0 deletions src/swift/tests/crud/AdvanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -922,4 +922,19 @@ class AdvanceTests: CRUDTestCase {

XCTAssertEqual(migratedTable ?? "", "sourceTable")
}

func testDefaultTemporaryDirectory() {
XCTAssertFalse(Database.setDefaultTemporaryDirectory("wrongDir"))

let tempDir = NSTemporaryDirectory().appending("/dbTempDir")
XCTAssertTrue(Database.setDefaultTemporaryDirectory(tempDir))

let getDirStatement = StatementPragma().pragma(Pragma(named: "temp_store_directory"))
var dir = WCDBAssertNoThrowReturned(try database.getValue(from: getDirStatement))
XCTAssertTrue(dir != nil && dir!.stringValue == tempDir)

XCTAssertTrue(Database.setDefaultTemporaryDirectory(""))
dir = WCDBAssertNoThrowReturned(try database.getValue(from: getDirStatement))
XCTAssertTrue(dir != nil && dir!.stringValue == "")
}
}

0 comments on commit 5cb84c5

Please sign in to comment.