核心功能: - ✅ Categories/Series双视图管理(category_view.rs + import_markdown.rs) - ✅ FUSE Multi-Volume支持(tree_type参数) - ✅ SSH/SFTP/SCP/rsync协议完整实现(4042行) - ✅ NFS/SMB Module Phase 1-3完成 - ✅ Archive Module Phase 1-4完成(2916行) - ✅ Download Center API完整实现 - ✅ S3兼容API实现(560行) Git配置修正: - ✅ 删除错误origin(gitea.momentry.ddns.net) - ✅ 删除m5max128(指向机器名) - ✅ 设置origin = m5max128gitea.momentry.ddns.net/admin/markbase - ✅ 设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase 数据清理: - ✅ 删除38个临时SQLite(保留accusys.sqlite、demo.sqlite) - ✅ 删除.bak、test_*.bin、调试脚本等临时文件 - ✅ 删除临时目录(build/、download files/、raid_test/等) - ✅ 更新.gitignore排除临时文件 架构优化: - 52个文件修改,2434行新增,4739行删除 - Workspace成员整合(16个crate) - 数据库状态:accusys.sqlite保留(主demo测试) 远程同步: - ✅ 准备推送到m5max128gitea(远程Gitea) - ✅ 准备推送到m4minigitea(本地Gitea)
460 lines
16 KiB
Swift
460 lines
16 KiB
Swift
import Foundation
|
|
|
|
public class FileLevelStorage {
|
|
|
|
// File Level Storage for MarkBaseFS
|
|
// No DriverKit Entitlement required
|
|
// Uses FileManager API for all storage operations
|
|
|
|
private let frameIndexTable: FrameIndexTable
|
|
private let fileManager = FileManager.default
|
|
|
|
// Multi-tier storage paths
|
|
private var nvmeTierPath: String = "/Volumes/MarkBaseFS_Test" // vdisk for POC
|
|
private var hddTierPath: String = "/Volumes/HDD_RAID"
|
|
private var objectStorageEndpoint: String = "http://localhost:9000"
|
|
|
|
// Object Storage Client
|
|
private var objectStorageClient: ObjectStorageClient?
|
|
|
|
// Performance tracking
|
|
private var writeSpeedMBps: Double = 0
|
|
private var readSpeedMBps: Double = 0
|
|
|
|
public init(frameIndexTable: FrameIndexTable) {
|
|
self.frameIndexTable = frameIndexTable
|
|
print("FileLevelStorage initializing...")
|
|
print(" - NVMe Tier (vdisk): \(nvmeTierPath)")
|
|
print(" - HDD Tier: \(hddTierPath)")
|
|
print(" - Object Storage: \(objectStorageEndpoint)")
|
|
|
|
// Initialize Object Storage Client
|
|
initializeObjectStorageClient()
|
|
}
|
|
|
|
private func initializeObjectStorageClient() {
|
|
let config = ObjectStorageConfig.minIODefault()
|
|
objectStorageClient = ObjectStorageClient(
|
|
endpoint: config.endpoint,
|
|
accessKey: config.accessKey,
|
|
secretKey: config.secretKey
|
|
)
|
|
|
|
print(" - Object Storage Client initialized")
|
|
}
|
|
|
|
// MARK: - vdisk Access Test
|
|
|
|
public func testVDiskAccess() {
|
|
print("\n=== FileLevelStorage: Multi-tier Storage Test ===")
|
|
|
|
// Test NVMe tier (vdisk)
|
|
testNVMeTier()
|
|
|
|
// Test HDD tier
|
|
testHDDTier()
|
|
|
|
// Test Object Storage tier
|
|
testObjectStorageTier()
|
|
|
|
// Test Multi-tier integration
|
|
testMultiTierIntegration()
|
|
|
|
print("\n=== Multi-tier Storage Test Complete ===")
|
|
}
|
|
|
|
private func testNVMeTier() {
|
|
print("\nTest: NVMe Tier (vdisk)")
|
|
testVDiskMount()
|
|
testFileOperations()
|
|
testFrameStorage()
|
|
testPerformance()
|
|
}
|
|
|
|
private func testHDDTier() {
|
|
print("\nTest: HDD Tier")
|
|
|
|
print(" - Checking HDD tier mount point: \(hddTierPath)")
|
|
|
|
if fileManager.fileExists(atPath: hddTierPath) {
|
|
print(" Result: ✅ SUCCESS - HDD tier mounted")
|
|
|
|
do {
|
|
let attributes = try fileManager.attributesOfFileSystem(forPath: hddTierPath)
|
|
|
|
if let totalSize = attributes[.systemSize] as? UInt64 {
|
|
let sizeGB = Double(totalSize) / (1024 * 1024 * 1024)
|
|
print(" Total Size: \(String(format: "%.2f", sizeGB)) GB")
|
|
}
|
|
} catch {
|
|
print(" ⚠️ Warning: Could not get file system attributes: \(error)")
|
|
}
|
|
} else {
|
|
print(" Result: ⚠️ WARNING - HDD tier not mounted")
|
|
print(" Note: HDD tier not available for POC testing")
|
|
}
|
|
}
|
|
|
|
private func testObjectStorageTier() {
|
|
print("\nTest: Object Storage Tier")
|
|
|
|
if let client = objectStorageClient {
|
|
client.testObjectOperations()
|
|
} else {
|
|
print(" Result: ⚠️ WARNING - Object Storage Client not initialized")
|
|
}
|
|
}
|
|
|
|
private func checkObjectStorageAvailable() -> Bool {
|
|
guard let client = objectStorageClient else {
|
|
return false
|
|
}
|
|
return client.testConnection()
|
|
}
|
|
|
|
private func testMultiTierIntegration() {
|
|
print("\nTest: Multi-tier Integration")
|
|
|
|
// Test tier selection logic
|
|
print(" - Testing tier selection logic...")
|
|
|
|
let videoId = "test_video_multi_tier"
|
|
let frameNumber: UInt64 = 0
|
|
|
|
// NVMe tier: hot frames (recently accessed)
|
|
print(" Tier for hot frame: \(getStorageTier(for: videoId, frameNumber: frameNumber, accessPattern: .hot))")
|
|
|
|
// HDD tier: cold frames (infrequently accessed)
|
|
print(" Tier for cold frame: \(getStorageTier(for: videoId, frameNumber: frameNumber, accessPattern: .cold))")
|
|
|
|
// Object Storage tier: archive frames (long-term storage)
|
|
print(" Tier for archive frame: \(getStorageTier(for: videoId, frameNumber: frameNumber, accessPattern: .archive))")
|
|
|
|
print(" - Multi-tier integration: ✅ SUCCESS")
|
|
}
|
|
|
|
private func testVDiskMount() {
|
|
print("Test 1: vdisk Mount Verification")
|
|
|
|
print(" - Checking vdisk mount point: \(nvmeTierPath)")
|
|
|
|
if fileManager.fileExists(atPath: nvmeTierPath) {
|
|
print(" Result: ✅ SUCCESS - vdisk mounted")
|
|
|
|
do {
|
|
let attributes = try fileManager.attributesOfFileSystem(forPath: nvmeTierPath)
|
|
|
|
if let totalSize = attributes[.systemSize] as? UInt64 {
|
|
let sizeGB = Double(totalSize) / (1024 * 1024 * 1024)
|
|
print(" Total Size: \(String(format: "%.2f", sizeGB)) GB")
|
|
}
|
|
|
|
if let freeSize = attributes[.systemFreeSize] as? UInt64 {
|
|
let freeGB = Double(freeSize) / (1024 * 1024 * 1024)
|
|
print(" Free Size: \(String(format: "%.2f", freeGB)) GB")
|
|
}
|
|
} catch {
|
|
print(" ⚠️ Warning: Could not get file system attributes: \(error)")
|
|
}
|
|
} else {
|
|
print(" Result: ❌ FAILED - vdisk not mounted")
|
|
}
|
|
}
|
|
|
|
private func testFileOperations() {
|
|
print("Test 2: File Operations")
|
|
|
|
let testFilePath = nvmeTierPath + "/markbase_test.txt"
|
|
let testContent = "MarkBaseFS File Level Storage Test\n".data(using: .utf8)!
|
|
|
|
// Write test
|
|
print(" - Write test")
|
|
do {
|
|
fileManager.createFile(atPath: testFilePath, contents: testContent, attributes: nil)
|
|
print(" Result: ✅ SUCCESS - File created")
|
|
} catch {
|
|
print(" Result: ❌ FAILED - \(error)")
|
|
}
|
|
|
|
// Read test
|
|
print(" - Read test")
|
|
do {
|
|
let readContent = fileManager.contents(atPath: testFilePath)
|
|
if readContent == testContent {
|
|
print(" Result: ✅ SUCCESS - File read correctly")
|
|
} else {
|
|
print(" Result: ❌ FAILED - Content mismatch")
|
|
}
|
|
} catch {
|
|
print(" Result: ❌ FAILED - \(error)")
|
|
}
|
|
|
|
// Delete test
|
|
print(" - Delete test")
|
|
do {
|
|
try fileManager.removeItem(atPath: testFilePath)
|
|
print(" Result: ✅ SUCCESS - File deleted")
|
|
} catch {
|
|
print(" Result: ❌ FAILED - \(error)")
|
|
}
|
|
}
|
|
|
|
private func testFrameStorage() {
|
|
print("Test 3: Frame Storage Integration")
|
|
|
|
// Create test frames
|
|
let testFrames = createTestFrames(count: 10)
|
|
|
|
print(" - Created \(testFrames.count) test frames")
|
|
|
|
// Insert frames to Frame Index Table
|
|
print(" - Inserting frames to Frame Index Table...")
|
|
|
|
for (index, frame) in testFrames.enumerated() {
|
|
let videoId = "test_video_\(index)"
|
|
let frameIndex = index
|
|
let frameFile = nvmeTierPath + "/frame_\(index).bin"
|
|
let frameOffset: Int = 0
|
|
let frameSize: Int = 1024
|
|
let frameChecksum = "test_checksum_\(index)"
|
|
|
|
frameIndexTable.insertFrame(
|
|
frameId: UUID().uuidString,
|
|
videoId: videoId,
|
|
frameIndex: frameIndex,
|
|
frameFile: frameFile,
|
|
frameOffset: frameOffset,
|
|
frameSize: frameSize,
|
|
frameChecksum: frameChecksum
|
|
)
|
|
|
|
print(" Inserted frame \(index): \(frameFile)")
|
|
}
|
|
|
|
// Verify frames
|
|
print(" - Verifying frames in Frame Index Table...")
|
|
|
|
let retrievedFrames = frameIndexTable.getFramesForVideo(videoId: "test_video_0")
|
|
|
|
if retrievedFrames.count == 10 {
|
|
print(" Result: ✅ SUCCESS - All frames retrieved")
|
|
} else {
|
|
print(" Result: ❌ FAILED - Expected 10 frames, got \(retrievedFrames.count)")
|
|
}
|
|
}
|
|
|
|
private func testPerformance() {
|
|
print("Test 4: Performance Test")
|
|
|
|
let performanceFilePath = nvmeTierPath + "/performance_test.bin"
|
|
|
|
// Write performance test
|
|
print(" - Write performance test")
|
|
let writeData = Data(count: 1024 * 1024 * 100) // 100 MB
|
|
|
|
let writeStart = Date()
|
|
do {
|
|
fileManager.createFile(atPath: performanceFilePath, contents: writeData, attributes: nil)
|
|
let writeEnd = Date()
|
|
let writeDuration = writeEnd.timeIntervalSince(writeStart)
|
|
writeSpeedMBps = 100.0 / writeDuration
|
|
|
|
print(" Write Speed: \(String(format: "%.2f", writeSpeedMBps)) MB/s")
|
|
print(" Result: ✅ SUCCESS")
|
|
} catch {
|
|
print(" Result: ❌ FAILED - \(error)")
|
|
}
|
|
|
|
// Read performance test
|
|
print(" - Read performance test")
|
|
let readStart = Date()
|
|
do {
|
|
let readData = fileManager.contents(atPath: performanceFilePath)
|
|
let readEnd = Date()
|
|
let readDuration = readEnd.timeIntervalSince(readStart)
|
|
let dataSizeMB = Double(readData?.count ?? 0) / (1024 * 1024)
|
|
readSpeedMBps = dataSizeMB / readDuration
|
|
|
|
print(" Read Speed: \(String(format: "%.2f", readSpeedMBps)) MB/s")
|
|
print(" Result: ✅ SUCCESS")
|
|
} catch {
|
|
print(" Result: ❌ FAILED - \(error)")
|
|
}
|
|
|
|
// Cleanup
|
|
do {
|
|
try fileManager.removeItem(atPath: performanceFilePath)
|
|
} catch {
|
|
print(" ⚠️ Warning: Could not cleanup performance test file")
|
|
}
|
|
|
|
// Performance summary
|
|
print(" Performance Summary:")
|
|
print(" Write Speed: \(String(format: "%.2f", writeSpeedMBps)) MB/s")
|
|
print(" Read Speed: \(String(format: "%.2f", readSpeedMBps)) MB/s")
|
|
|
|
if writeSpeedMBps > 100 && readSpeedMBps > 100 {
|
|
print(" ✅ Performance meets POC requirements")
|
|
} else {
|
|
print(" ⚠️ Performance below POC requirements")
|
|
}
|
|
}
|
|
|
|
// MARK: - Frame Operations
|
|
|
|
public func storeFrame(videoId: String, frameNumber: UInt64, data: Data) -> Bool {
|
|
let filePath = nvmeTierPath + "/videos/\(videoId)/frame_\(frameNumber).bin"
|
|
|
|
// Create directory if needed
|
|
let dirPath = nvmeTierPath + "/videos/\(videoId)"
|
|
do {
|
|
try fileManager.createDirectory(atPath: dirPath, withIntermediateDirectories: true)
|
|
} catch {
|
|
print("Error creating directory: \(error)")
|
|
return false
|
|
}
|
|
|
|
// Write frame data
|
|
do {
|
|
fileManager.createFile(atPath: filePath, contents: data, attributes: nil)
|
|
|
|
// Insert to Frame Index Table
|
|
frameIndexTable.insertFrame(
|
|
frameId: UUID().uuidString,
|
|
videoId: videoId,
|
|
frameIndex: Int(frameNumber),
|
|
frameFile: filePath,
|
|
frameOffset: 0,
|
|
frameSize: data.count,
|
|
frameChecksum: "stored_checksum"
|
|
)
|
|
|
|
return true
|
|
} catch {
|
|
print("Error storing frame: \(error)")
|
|
return false
|
|
}
|
|
}
|
|
|
|
public func retrieveFrame(videoId: String, frameNumber: UInt64) -> Data? {
|
|
// Get frame from Frame Index Table
|
|
let frames = frameIndexTable.getFramesForVideo(videoId: videoId)
|
|
|
|
for frame in frames {
|
|
if let frameIndex = frame["frame_index"] as? Int, frameIndex == Int(frameNumber) {
|
|
// Read frame data from file
|
|
if let frameFile = frame["frame_file"] as? String {
|
|
do {
|
|
let data = fileManager.contents(atPath: frameFile)
|
|
return data
|
|
} catch {
|
|
print("Error retrieving frame: \(error)")
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
public func deleteFrame(videoId: String, frameNumber: UInt64) -> Bool {
|
|
// Get frame from Frame Index Table
|
|
let frames = frameIndexTable.getFramesForVideo(videoId: videoId)
|
|
|
|
for frame in frames {
|
|
if let frameIndex = frame["frame_index"] as? Int, frameIndex == Int(frameNumber) {
|
|
// Delete frame file
|
|
if let frameFile = frame["frame_file"] as? String, let frameId = frame["frame_id"] as? String {
|
|
do {
|
|
try fileManager.removeItem(atPath: frameFile)
|
|
|
|
// Delete from Frame Index Table
|
|
frameIndexTable.deleteFrame(frameId: frameId)
|
|
|
|
return true
|
|
} catch {
|
|
print("Error deleting frame: \(error)")
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// MARK: - Multi-tier Storage
|
|
|
|
public enum AccessPattern {
|
|
case hot // Recently accessed, high performance required
|
|
case cold // Infrequently accessed, moderate performance
|
|
case archive // Long-term storage, low performance acceptable
|
|
}
|
|
|
|
public func getStorageTier(for videoId: String, frameNumber: UInt64, accessPattern: AccessPattern = .hot) -> StorageTier {
|
|
// Determine storage tier based on access pattern
|
|
switch accessPattern {
|
|
case .hot:
|
|
return .nvme // NVMe tier for hot frames
|
|
case .cold:
|
|
return .hdd // HDD tier for cold frames
|
|
case .archive:
|
|
return .objectStorage // Object Storage tier for archive frames
|
|
}
|
|
}
|
|
|
|
public func getStorageTier(for videoId: String) -> StorageTier {
|
|
// Legacy function for compatibility
|
|
return getStorageTier(for: videoId, frameNumber: 0, accessPattern: .hot)
|
|
}
|
|
|
|
public func migrateToTier(videoId: String, targetTier: StorageTier) -> Bool {
|
|
// Migrate video data to target tier
|
|
// For POC, migration is not implemented
|
|
|
|
print("Migration to \(targetTier) not implemented for POC")
|
|
return false
|
|
}
|
|
|
|
// MARK: - Helper Functions
|
|
|
|
private func createTestFrames(count: Int) -> [Data] {
|
|
var frames: [Data] = []
|
|
|
|
for i in 0..<count {
|
|
let frameData = Data(count: 1024) // 1 KB test frame
|
|
frames.append(frameData)
|
|
}
|
|
|
|
return frames
|
|
}
|
|
|
|
public func getStorageStats() -> StorageStats {
|
|
let objectStorageAvailable = checkObjectStorageAvailable()
|
|
|
|
return StorageStats(
|
|
writeSpeedMBps: writeSpeedMBps,
|
|
readSpeedMBps: readSpeedMBps,
|
|
nvmeTierAvailable: fileManager.fileExists(atPath: nvmeTierPath),
|
|
hddTierAvailable: fileManager.fileExists(atPath: hddTierPath),
|
|
objectStorageAvailable: objectStorageAvailable
|
|
)
|
|
}
|
|
}
|
|
|
|
// MARK: - Supporting Types
|
|
|
|
public enum StorageTier {
|
|
case nvme
|
|
case hdd
|
|
case objectStorage
|
|
}
|
|
|
|
public struct StorageStats {
|
|
let writeSpeedMBps: Double
|
|
let readSpeedMBps: Double
|
|
let nvmeTierAvailable: Bool
|
|
let hddTierAvailable: Bool
|
|
let objectStorageAvailable: Bool
|
|
} |