/*
* @Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*/
package memorycache
import std.fs.*
import std.posix
import std.random.*
public class LruDiskCache {
public static let DEFAULT_MAX_SIZE: Int64 = 3 * 1024 * 1024
public static let DEFAULT_PATH: String = "./cache"
public static let DEFAULT_NAME: String = "LruDiskCache"
private var path: String = ""
private var size: Int64 = 0
private var maxSize: Int64 = 0
private var cacheMap: CustomMap<String, DiskCacheEntry> = CustomMap<String, DiskCacheEntry>()
private var id: UInt64 = 0
public init(path!: String = DEFAULT_PATH + FileUtils.SEPARATOR + DEFAULT_NAME, maxSize!: Int64 = DEFAULT_MAX_SIZE) {
let random: Random = Random()
id = random.nextBits(60)
this.path = path + "/${id}"
setMaxSize(maxSize)
trimToSize()
var tempPath: String = path + "/${id}"
var sInstance = FileUtils.getInstance()
while (sInstance.existFolder(path+"/${id}")) {
id = random.nextBits(60)
}
try {
if (!sInstance.existFolder(tempPath)) {
sInstance.createFolder(tempPath, recursive: true)
}
} catch (e: Exception) {
throw MemoryCacheException("create cache folder failed")
}
if (!tempPath.endsWith("/")) {
this.path = tempPath + FileUtils.SEPARATOR
}
}
public func getPath(): String {
return this.path
}
public func getId(): UInt64 {
return this.id
}
public func getCacheMap(): CustomMap<String, DiskCacheEntry> {
return this.cacheMap
}
public func getSize(): Int64 {
return this.size
}
public func getMaxSize(): Int64 {
return this.maxSize
}
public func set(key: String, context: String) {
if (key.isEmpty()) {
throw MemoryCacheException("empty key value")
}
if (context.size > this.maxSize) {
throw MemoryCacheException("context size is bigger than maxSize")
}
var tempsize = context.size
size = size + tempsize
putCacheMap(key, tempsize)
trimToSize()
FileUtils.sInstance.writeNewFile(path + key, context)
}
public func set(key: String, context: Array<UInt8>) {
if (key.isEmpty()) {
throw MemoryCacheException("empty key value")
}
if (context.size > this.maxSize) {
throw MemoryCacheException("context size is bigger than maxSize")
}
var tempsize = context.size
size = size + tempsize
putCacheMap(key, tempsize)
trimToSize()
FileUtils.sInstance.writeNewFile(path + key, context)
}
public operator func [](key: String, context: String) {
set(key, context)
}
public operator func [](key: String, context: Array<UInt8>) {
set(key, context)
}
public func get(key: String): Array<UInt8> {
var tempPath: String = path + key
if (FileUtils.sInstance.exists(tempPath)) {
var res = FileUtils.sInstance.readFile(path + key)
this.putCacheMap(key, res.size)
return res
}
return Array<UInt8>()
}
public func contains(key: String): Bool {
if (cacheMap.hasKey(key)) {
return true
}
if (FileUtils.sInstance.exists(path + key)) {
if (posix.isDir(path)) {
return false
}
return true
}
return false
}
public func remove(key: String): Unit {
if (cacheMap.hasKey(key)) {
var tempPath: String = path + key
var tempsize = FileUtils.sInstance.getFileSize(tempPath)
FileUtils.sInstance.deleteFile(tempPath)
cacheMap.remove(key)
size = size - tempsize
}
}
public func setMaxSize(size: Int64) {
if (size <= 0 || size > DEFAULT_MAX_SIZE) {
throw MemoryCacheException("size must be greater than 0 and less than DEFAULT_MAX_SIZE")
}
this.maxSize = size
trimToSize()
}
func putCacheMap(key: String, size: Int64) {
if (size > 0) {
cacheMap.put(key, DiskCacheEntry(key, size))
} else {
cacheMap.put(key, DiskCacheEntry(key, size))
}
}
func trimToSize() {
var tempkey = ""
var tempsize = 0
while (size > maxSize) {
tempkey = cacheMap.getFirstKey()
var tempPath = path + tempkey
var sInstance = FileUtils.sInstance
tempsize = sInstance.getFileSize(tempPath)
if (tempsize > 0) {
size = size - tempsize
}
sInstance.deleteFile(tempPath)
cacheMap.remove(tempkey)
}
}
}