Update ^C Handling during upload|download operations

* Update ^C Handling during upload|download operations
This commit is contained in:
abraunegg 2024-04-28 09:05:30 +10:00
parent 39c04642cd
commit bf029b4676
5 changed files with 46 additions and 67 deletions

View file

@ -161,13 +161,14 @@ class CurlResponse {
class CurlEngine {
__gshared CurlEngine[] curlEnginePool;
// Shared pool of CurlEngine instances accessible across all threads
__gshared CurlEngine[] curlEnginePool; // __gshared is used to declare a variable that is shared across all threads
HTTP http;
File uploadFile;
CurlResponse response;
bool keepAlive;
ulong dnsTimeout;
CurlResponse response;
File uploadFile;
string internalThreadId;
this() {
@ -176,30 +177,26 @@ class CurlEngine {
internalThreadId = generateAlphanumericString();
}
~this() {
// The destructor should only clean up resources owned directly by this instance
addLogEntry("CurlEngine DESTRUCTOR CALLED", ["debug"]);
addLogEntry("CurlEngine DESTRUCTOR CALLED");
// Avoid modifying or destroying shared/static resources here
~this() {
// Is the file still open?
if (uploadFile.isOpen()) {
uploadFile.close();
}
// Cleanup class memory usage
object.destroy(uploadFile); // Destroy, however we cant set to null
// Is 'response' cleared?
if (response !is null) {
object.destroy(response); // Destroy, then set to null
response = null;
internalThreadId = null;
}
// Is the actual http instance is stopped?
if (!http.isStopped) {
// instance was not stopped .. need to stop it
addLogEntry("CurlEngine DESTRUCTOR HTTP INSTANCE WAS NOT STOPPED - STOPPING", ["debug"]);
// HTTP instance was not stopped .. need to stop it
http.shutdown();
}
object.destroy(http); // Destroy, however we cant set to null
}
}
static CurlEngine getCurlInstance() {
synchronized (CurlEngine.classinfo) {
@ -232,6 +229,7 @@ class CurlEngine {
synchronized (CurlEngine.classinfo) {
// What is the current pool size
addLogEntry("CURL ENGINES TO RELEASE: " ~ to!string(curlEnginePool.length), ["debug"]);
addLogEntry("CURL ENGINES TO RELEASE: " ~ to!string(curlEnginePool.length));
// Safely iterate and clean up each CurlEngine instance
foreach (curlEngineInstance; curlEnginePool) {
@ -253,12 +251,11 @@ class CurlEngine {
// Destroy all curl instances
static void destroyAllCurlInstances() {
addLogEntry("DESTROY ALL CURL ENGINES", ["debug"]);
addLogEntry("DESTROY ALL CURL ENGINES");
// Release all 'curl' instances
releaseAllCurlInstances();
// Destroy curlEnginePool, set to null
object.destroy(curlEnginePool);
curlEnginePool = null;
}
// We are releasing a curl instance back to the pool

View file

@ -53,6 +53,7 @@ class LogBuffer {
flushThread.start();
}
// The destructor should only clean up resources owned directly by this instance
~this() {
object.destroy(bufferLock);
object.destroy(condReady);

View file

@ -1367,13 +1367,8 @@ extern(C) nothrow @nogc @system void exitHandler(int value) {
assumeNoGC ( () {
addLogEntry("\nReceived termination signal, initiating cleanup");
// Wait for all parallel jobs that depend on the database to complete
addLogEntry("Waiting for any existing upload|download process to complete");
taskPool.finish(true);
// Force kill any running threads
//addLogEntry("Forcing any active thread to exit");
//taskPool.finish(false);
syncEngineInstance.shutdown();
// Perform the shutdown process
performSynchronisedExitProcess("exitHandler");
@ -1403,17 +1398,16 @@ void performSynchronisedExitProcess(string scopeCaller = null) {
shutdownOneDriveWebhook();
// Shutdown the client side filtering objects
shutdownSelectiveSync();
// Destroy all 'curl' instances
destroyCurlInstances();
// Shutdown the sync engine
shutdownSyncEngine();
// Shutdown any local filesystem monitoring
shutdownFilesystemMonitor();
// Shutdown the database
shutdownDatabase();
// Destroy all 'curl' instances
destroyCurlInstances();
// Shutdown the application configuration objects
shutdownAppConfig();
} catch (Exception e) {
addLogEntry("Error during performStandardExitProcess: " ~ e.toString(), ["error"]);
}
@ -1458,7 +1452,7 @@ void shutdownSelectiveSync() {
void shutdownSyncEngine() {
if (syncEngineInstance !is null) {
addLogEntry("Shutdown Sync Engine instance", ["debug"]);
//syncEngineInstance.shutdown(); - potentially need this and also check for a ~this() for class cleanup
syncEngineInstance.shutdown(); // Make sure any running thread completes first
object.destroy(syncEngineInstance);
syncEngineInstance = null;
}

View file

@ -111,18 +111,20 @@ class OneDriveApi {
siteSearchUrl = appConfig.globalGraphEndpoint ~ "/v1.0/sites?search";
siteDriveUrl = appConfig.globalGraphEndpoint ~ "/v1.0/sites/";
// Subscriptions
subscriptionUrl = appConfig.globalGraphEndpoint ~ "/v1.0/subscriptions";
}
// The destructor should only clean up resources owned directly by this instance
~this() {
// We cant destroy 'appConfig' here as this leads to a segfault
object.destroy(curlEngine);
object.destroy(response);
if (curlEngine !is null) {
curlEngine = null;
}
if (response !is null) {
response = null;
}
}
// Initialise the OneDrive API class
bool initialise(bool keepAlive=true) {
@ -353,12 +355,6 @@ class OneDriveApi {
return authorised;
}
// Reinitialise the OneDrive API class
bool reinitialise() {
releaseCurlEngine();
return initialise(this.keepAlive);
}
// If the API has been configured correctly, print the items that been configured
void debugOutputConfiguredAPIItems() {
// Debug output of configured URL's
@ -1120,7 +1116,6 @@ class OneDriveApi {
// Wrapper function for all requests to OneDrive API
// - This should throw a OneDriveException so that this exception can be handled appropriately elsewhere in the application
private JSONValue oneDriveErrorHandlerWrapper(CurlResponse delegate(CurlResponse response) executer, bool validateJSONResponse, string callingFunction, int lineno) {
// Create a new 'curl' response
response = new CurlResponse();

View file

@ -185,7 +185,7 @@ class SyncEngine {
this(ApplicationConfig appConfig, ItemDatabase itemDB, ClientSideFiltering selectiveSync) {
// Create the specific task pool to process items in parallel
this.processPool = new TaskPool(to!int(appConfig.getValueLong("threads")));
processPool = new TaskPool(to!int(appConfig.getValueLong("threads")));
addLogEntry("PROCESS POOL WORKER THREADS: " ~ to!string(processPool.size), ["debug"]);
// Configure the class varaible to consume the application configuration
@ -302,21 +302,13 @@ class SyncEngine {
}
}
// The destructor should only clean up resources owned directly by this instance
~this() {
this.processPool.finish(true);
object.destroy(this.processPool); // Destroy, then set to null
this.processPool = null;
object.destroy(this.appConfig); // Destroy, then set to null
this.appConfig = null;
object.destroy(this.itemDB); // Destroy, then set to null
this.itemDB = null;
object.destroy(this.selectiveSync); // Destroy, then set to null
this.selectiveSync = null;
processPool.finish(true);
}
// Initialise the Sync Engine class
bool initialise() {
// Control whether the worker threads are daemon threads. A daemon thread is automatically terminated when all non-daemon threads have terminated.
processPool.isDaemon(true);
@ -387,15 +379,15 @@ class SyncEngine {
// Shutdown this API instance, as we will create API instances as required, when required
oneDriveApiInstance.releaseCurlEngine();
// Free object and memory
//object.destroy(oneDriveApiInstance);
//oneDriveApiInstance = null;
return true;
}
// Shutdown the sync engine, wait for anything in processPool to complete
void shutdown() {
addLogEntry("SYNC-ENGINE: Waiting for all internal threads to complete", ["debug"]);
processPool.finish(true);
}
// Get Default Drive Details for this Account
void getDefaultDriveDetails() {