Skip to content

Commit

Permalink
fix: clean up chunk memory (#101)
Browse files Browse the repository at this point in the history
* avoid keeping a reference to the file chunk in ChunkWorker

When the Worker actor loops over a file, it does not always deallocate
file chunks until the loop completes.

Because each ChunkWorker is intended to be only used once, it is not
necessary to keep a reference to its file chunk beyond the upload task
call.

---------

Co-authored-by: AJ Lauer Barinov <[email protected]>
  • Loading branch information
tomkordic and andrewjl-mux authored Mar 15, 2024
1 parent d582130 commit 1cf9783
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
19822A772A4CA69700CFA822 /* UploadCTA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19822A662A4CA69700CFA822 /* UploadCTA.swift */; };
19822A792A4CA69700CFA822 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19822A682A4CA69700CFA822 /* ImagePicker.swift */; };
19DCD95B2A4CA567001FBBF6 /* MuxUploadSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 19DCD95A2A4CA567001FBBF6 /* MuxUploadSDK */; };
F38876D22B86DCFB00B82A86 /* MuxUploadSDK in Frameworks */ = {isa = PBXBuildFile; productRef = F38876D12B86DCFB00B82A86 /* MuxUploadSDK */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -36,6 +37,13 @@
remoteGlobalIDString = 358E3C7629A92167005261CB;
remoteInfo = "Test App";
};
F38876CB2B86DBEB00B82A86 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 358E3C6F29A92167005261CB /* Project object */;
proxyType = 1;
remoteGlobalIDString = 358E3C7629A92167005261CB;
remoteInfo = SwiftUploadSDKExample;
};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
Expand All @@ -60,6 +68,7 @@
19DCD9592A4CA546001FBBF6 /* swift-upload-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "swift-upload-sdk"; path = ../..; sourceTree = "<group>"; };
358E3C7729A92167005261CB /* SwiftUploadSDKExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUploadSDKExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftUploadSDKExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F38876C72B86DBEB00B82A86 /* .xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = .xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -78,6 +87,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F38876C42B86DBEB00B82A86 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F38876D22B86DCFB00B82A86 /* MuxUploadSDK in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
Expand Down Expand Up @@ -175,6 +192,7 @@
358E3CC329A9221F005261CB /* Packages */,
19822A502A4CA69700CFA822 /* SwiftUploadSDKExample */,
19822A7A2A4CA6A300CFA822 /* SwiftUploadSDKExampleTests */,
F38876C82B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */,
358E3C7829A92167005261CB /* Products */,
358E3CC529A9223B005261CB /* Frameworks */,
);
Expand All @@ -185,6 +203,7 @@
children = (
358E3C7729A92167005261CB /* SwiftUploadSDKExample.app */,
358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */,
F38876C72B86DBEB00B82A86 /* .xctest */,
);
name = Products;
sourceTree = "<group>";
Expand All @@ -204,6 +223,13 @@
name = Frameworks;
sourceTree = "<group>";
};
F38876C82B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */ = {
isa = PBXGroup;
children = (
);
path = SwiftUploadSDKExampleUnitTests;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -245,14 +271,35 @@
productReference = 358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
F38876C62B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = F38876CD2B86DBEB00B82A86 /* Build configuration list for PBXNativeTarget "SwiftUploadSDKExampleUnitTests" */;
buildPhases = (
F38876C32B86DBEB00B82A86 /* Sources */,
F38876C42B86DBEB00B82A86 /* Frameworks */,
F38876C52B86DBEB00B82A86 /* Resources */,
);
buildRules = (
);
dependencies = (
F38876CC2B86DBEB00B82A86 /* PBXTargetDependency */,
);
name = SwiftUploadSDKExampleUnitTests;
packageProductDependencies = (
F38876D12B86DCFB00B82A86 /* MuxUploadSDK */,
);
productName = SwiftUploadSDKExampleUnitTests;
productReference = F38876C72B86DBEB00B82A86 /* .xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
358E3C6F29A92167005261CB /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1420;
LastSwiftUpdateCheck = 1500;
LastUpgradeCheck = 1420;
TargetAttributes = {
358E3C7629A92167005261CB = {
Expand All @@ -262,6 +309,10 @@
CreatedOnToolsVersion = 14.2;
TestTargetID = 358E3C7629A92167005261CB;
};
F38876C62B86DBEB00B82A86 = {
CreatedOnToolsVersion = 15.0.1;
TestTargetID = 358E3C7629A92167005261CB;
};
};
};
buildConfigurationList = 358E3C7229A92167005261CB /* Build configuration list for PBXProject "SwiftUploadSDKExample" */;
Expand All @@ -273,12 +324,16 @@
Base,
);
mainGroup = 358E3C6E29A92167005261CB;
packageReferences = (
F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */,
);
productRefGroup = 358E3C7829A92167005261CB /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
358E3C7629A92167005261CB /* SwiftUploadSDKExample */,
358E3C9029A92168005261CB /* SwiftUploadSDKExampleTests */,
F38876C62B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */,
);
};
/* End PBXProject section */
Expand All @@ -301,6 +356,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F38876C52B86DBEB00B82A86 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
Expand Down Expand Up @@ -333,6 +395,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
F38876C32B86DBEB00B82A86 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
Expand All @@ -341,6 +410,11 @@
target = 358E3C7629A92167005261CB /* SwiftUploadSDKExample */;
targetProxy = 358E3C9229A92168005261CB /* PBXContainerItemProxy */;
};
F38876CC2B86DBEB00B82A86 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 358E3C7629A92167005261CB /* SwiftUploadSDKExample */;
targetProxy = F38876CB2B86DBEB00B82A86 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */

/* Begin XCBuildConfiguration section */
Expand Down Expand Up @@ -481,7 +555,6 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-App";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -513,7 +586,6 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-App";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -531,7 +603,6 @@
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-AppUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
Expand All @@ -549,7 +620,6 @@
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-AppUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
Expand All @@ -558,6 +628,49 @@
};
name = Release;
};
F38876CE2B86DBEB00B82A86 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUploadSDKExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftUploadSDKExample";
};
name = Debug;
};
F38876CF2B86DBEB00B82A86 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUploadSDKExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftUploadSDKExample";
};
name = Release;
};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
Expand Down Expand Up @@ -588,13 +701,38 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F38876CD2B86DBEB00B82A86 /* Build configuration list for PBXNativeTarget "SwiftUploadSDKExampleUnitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F38876CE2B86DBEB00B82A86 /* Debug */,
F38876CF2B86DBEB00B82A86 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/muxinc/swift-upload-sdk";
requirement = {
branch = main;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
19DCD95A2A4CA567001FBBF6 /* MuxUploadSDK */ = {
isa = XCSwiftPackageProductDependency;
productName = MuxUploadSDK;
};
F38876D12B86DCFB00B82A86 /* MuxUploadSDK */ = {
isa = XCSwiftPackageProductDependency;
package = F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */;
productName = MuxUploadSDK;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 358E3C6F29A92167005261CB /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@
ReferencedContainer = "container:SwiftUploadSDKExample.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F38876C62B86DBEB00B82A86"
BuildableName = "SwiftUploadSDKExampleUnitTests.xctest"
BlueprintName = "SwiftUploadSDKExampleUnitTests"
ReferencedContainer = "container:SwiftUploadSDKExample.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
50 changes: 45 additions & 5 deletions Sources/MuxUploadSDK/InternalUtilities/ChunkedFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,47 @@ class ChunkedFile {
func readNextChunk() -> Result<FileChunk, Error> {
SDKLogger.logger?.info("--readNextChunk(): called")
do {
guard fileHandle != nil else {
guard let fileHandle else {
return Result.failure(ChunkedFileError.invalidState("readNextChunk() called but the file was not open"))
}
return try Result.success(doReadNextChunk())

guard let fileURL = fileURL else {
return Result.failure(ChunkedFileError.invalidState("Missing file url."))
}
var data : Data?
try autoreleasepool {
data = try fileHandle.read(upToCount: chunkSize)
}

let fileSize = try fileManager.fileSizeOfItem(
atPath: fileURL.path
)

guard let data = data else {
// Called while already at the end of the file. We read zero bytes, "ending" at the end of the file
return .success(
FileChunk(
startByte: fileSize,
endByte: fileSize,
totalFileSize: fileSize,
chunkData: Data(capacity: 0)
)
)
}

let chunkLength = data.count
let updatedFilePosition = filePos + UInt64(chunkLength)

let chunk = FileChunk(
startByte: self.filePos,
endByte: updatedFilePosition,
totalFileSize: fileSize,
chunkData: data
)

state?.filePosition = updatedFilePosition

return .success(chunk)
} catch {
return Result.failure(ChunkedFileError.fileHandle(error))
}
Expand Down Expand Up @@ -91,8 +128,11 @@ class ChunkedFile {
guard let fileHandle = fileHandle, let fileURL = fileURL else {
throw ChunkedFileError.invalidState("doReadNextChunk called without file handle. Did you call open()?")
}
let data = try fileHandle.read(upToCount: chunkSize)

var data : Data?
try autoreleasepool {
data = try fileHandle.read(upToCount: chunkSize)
}

let fileSize = try fileManager.fileSizeOfItem(
atPath: fileURL.path
)
Expand Down Expand Up @@ -131,7 +171,7 @@ struct FileChunk {
/// Exclusive
let endByte: UInt64
let totalFileSize: UInt64
let chunkData: Data
var chunkData: Data

func size() -> Int {
return Int(endByte - startByte) // This is safe for any reasonable chunk size
Expand Down
Loading

0 comments on commit 1cf9783

Please sign in to comment.