IndexedDB 删除的对象从未从 Chrome 上的磁盘中删除

use*_*858 5 google-chrome indexeddb typescript

我正在尝试创建一个每秒接收产品的应用程序,并使用 LRU 策略更新固定大小(~ 300 MB)的数据库。虽然我在添加新产品和从数据库中删除它们方面没有例外,但 Chrome 似乎永远不会删除 .ldb 和 .bak 文件。因此,我花费了几千兆字节的硬盘,而且总是达到配额限制。相同的代码在 Firefox 上完美运行。有人可以解释一下我做错了什么吗?您可以在下面找到代码。

startExperiment(300 * 1024 * 1024);

function startExperiment(lrusize:number) {

var j = 0;

var productsToInsert = new HashMap<number, Product>();

window.indexedDB.deleteDatabase("ExampleDatabase");
var versionNumber = 1;
var stats = new Stats();
var sizeOfDatabase = 0;
var db = new ProductDatabase('ExampleDatabase', versionNumber, () => {
    db.getSizeOfDatabase((result) => {
        if(result == null) {
            sizeOfDatabase = 0;
        } else {
            sizeOfDatabase = result;
        }
    });
});





function randomizeArray() {
    var numOfMBS = Math.floor((Math.random() * (10 - 2) + 2) * 1024 * 1024);
    var bytearray = new Uint8Array(numOfMBS.valueOf());
    for (var i = 0; i < bytearray.length; i++) {
        bytearray[i] = Math.random() * (100 - 1) + 1;
    }
    return bytearray;
}


setInterval(function () {
    var readAverage = stats.getReadTimesAverage();
    var writeAverage = stats.getWriteTimesAverage();
    var deleteAverage = stats.getDeleteTimesAverage();

    console.log("Num of insertions : " + j + " | Read average : " + readAverage + " | Write average : " + writeAverage + " | Delete average : " + deleteAverage);
}, 5000);

setInterval(function () {
    var bytearray = randomizeArray();
    var identifier = j++;
    var timestamp = Date.now();
    db.getProduct(identifier, (product) => {
        if (product == null) {
            var newProduct = new Product(identifier, timestamp, 0, bytearray);
            var size = memorySizeOf(newProduct);
            newProduct.sizeInBytes = size;
            productsToInsert.set(identifier, newProduct);
        }
    });
}, 1000);


function updateLRU() {
    var tmpList:Product[] = [];
    var keys = productsToInsert.keys();
    var currentBytesToBeInserted = 0;
    for (var i = 0; i < keys.length; i++) {
        var product = productsToInsert.get(keys[i]);
        tmpList.push(product);
        currentBytesToBeInserted += product.sizeInBytes;
    }

    var currentSize = sizeOfDatabase + currentBytesToBeInserted;
    if (currentSize > lrusize) {
        var bytesToRemove = currentSize - lrusize;
        db.deleteProducts(bytesToRemove, stats, () => {
            sizeOfDatabase -= bytesToRemove;
            addFragments(tmpList);
        });
    } else {
        addProducts(tmpList);
    }
}


function addProducts(tmpList:Product[]) {

    var product = tmpList[0];
    var startAddProductTs = Date.now();
    db.addProduct(product, () => {
        var stopAddProductTs = Date.now();
        stats.addWriteTimes(stopAddProductTs - startAddProductTs);
        sizeOfDatabase += product.sizeInBytes;
        tmpList.shift();
        productsToInsert.delete(product.productId);
        if(tmpList.length > 0) {
            addProducts(tmpList);
        } else {
            db.addDBSize(sizeOfDatabase, () => {

            });
        }
    });
}

setInterval(function () {

    updateLRU();

}, 20000);


}





class ProductDatabase {

private db;

constructor(private name:string, private version:number, callback:() => void) {
    this.openDatabase(callback);

}


openDatabase(callback:() => void) {
    var openDatabaseRequest = window.indexedDB.open(this.name, this.version);
    openDatabaseRequest.onupgradeneeded = this.upgrade;
    openDatabaseRequest.onsuccess = () => {
        this.db = openDatabaseRequest.result;
        callback();
    }

}

upgrade(event:any) {
    var store = event.target.result.createObjectStore("products", {keyPath: 'productId'});
    store.createIndex('by_timestamp', "timestamp", {unique: true});
    event.target.result.createObjectStore("dbsize", {keyPath: 'sizeId'});
}


getProduct(productId:number, callback:(result:Product) => void) {


    var productStore = this.db.transaction(["products"], "readonly").objectStore('products');

    var query = productStore.get(productId);

    query.onsuccess = () => {
        var product = query.result;
        callback(product);
    }

    query.onerror = () => {
        console.error("Read product error : " + query.error);
    }


}


addDBSize(dbSize:number, callback:() => void) {


    var transaction = this.db.transaction('dbsize', 'readwrite');
    var productStore = transaction.objectStore('dbsize');
    var newSize = {'sizeId': 1, 'bytelength': dbSize};
    var request = productStore.put(newSize);


    request.onerror = () => {
        console.log("Unsuccessful request with error : " + request.error);

    }


    transaction.oncomplete = () => {
        callback();
    }

    transaction.onerror = () => {
        console.error("fucking error : " + transaction.error);

    }


    transaction.onabort = () => {
        console.error("Shit. transaction is aborted with error : " + transaction.error);

    }


}

addCachedProducts(productList:Array<Product>, callback:() => void) {


    var transaction = this.db.transaction('products', 'readwrite');
    var productStore = transaction.objectStore('products');
    for (var i = 0; i < productList.length; i++) {
        productStore.add(productList[i]);
    }

    transaction.oncomplete = () => {
        callback();
    }

    transaction.onabort = () => {
        console.error("Shit. transaction is aborted with error : " + transaction.error);
    }

}

getNumberOfProducts(callback:(result:number) => void) {

    var productStore = this.db.transaction('products', 'readonly').objectStore('products');
    var query = productStore.count();
    query.onsuccess = () => {
        var result = query.result;
        callback(result);
    }

    query.onerror = () => {
        console.error("Read number of products error : " + query.error);
    }

}

getSizeOfDatabase(callback:(result:number) => void) {

    var productStore = this.db.transaction('dbsize', "readonly").objectStore('dbsize');

    var query = productStore.get(1);

    query.onsuccess = () => {
        var product = query.result;
        callback(product);
    }

    query.onerror = () => {
        console.error("Read databasesize error : " + query.error);
    }

}

deleteProducts(numOfBytes:number, stats:Stats, callback:() => void) {


    var transaction = this.db.transaction('products', 'readwrite');
    var productStore = transaction.objectStore('products');
    var index = productStore.index('by_timestamp');

    var request = index.openCursor();
    request.onsuccess = function () {
        var cursor = request.result;
        if (cursor) {
            var cursorBytes = cursor.value.sizeInBytes;
            var startDeleteTs = Date.now();
            var deleteRequest = cursor.delete();
            deleteRequest.onsuccess = () => {
                var stopDeleteTs = Date.now();
                stats.addDeleteTimes(stopDeleteTs - startDeleteTs);
                numOfBytes -= cursorBytes;
                if (numOfBytes > 0) {
                    cursor.continue();
                }
            }

            deleteRequest.onerror = () => {
                console.error("Delete product error : " + deleteRequest.error);
            }
        }

    }


    transaction.oncomplete = () => {
        callback();
    }

    transaction.onabort = () => {
        console.log("Delete transaction aborted with error : " + transaction.error);
    }

}


addProduct(product:Product, callback:() => void) {


        var transaction = this.db.transaction('products', 'readwrite');
        var productStore = transaction.objectStore('products');
        var request = productStore.put(product);


        request.onerror = () => {
            console.log("Unsuccessful request with error : " + request.error);
        }


        transaction.oncomplete = () => {
            callback();
        }

        transaction.onerror = () => {
            console.error("fucking error : " + transaction.error);
        }


        transaction.onabort = () => {
            console.error("Shit. transaction is aborted with error : " + transaction.error);
        }



}

}
Run Code Online (Sandbox Code Playgroud)

dum*_*ter 3

在 Chrome 中,通过 IndexedDB API 删除数据与从磁盘删除数据之间存在延迟。通常这样就可以了。但根据我的经验,有时它永远不会从磁盘中删除,当用户超出其配额时,这非常糟糕,因为即使删除所有内容,也永远无法存储更多数据