IndexedDB "updates" 每次浏览器重新启动并删除数据
IndexedDB "updates" every browser restart and erases data
我编写了一个 Firefox WebExtension,它从网站下载数据文件并使用 IndexedDB store/update 数据。创建的 .SQLite
文件大小约为 2GB。每当我重新启动 Firefox 时,扩展都会执行 onupgradeneeded
事件,即使我总是使用版本“1”。我在那个事件中创建了数据库对象存储和索引,所以 我所有的数据最终都被删除了。
唯一没有发生的情况是当我在下载或存储数据时关闭 Firefox。 下次我启动 Firefox 时,它不会执行该事件(应该是这样)。然后它会按照编程的方式继续更新数据库。
我安装了 SQLite 管理器扩展,希望我能找出导致数据库问题的原因,但对我来说没有什么是显而易见的。
这是我的部分背景脚本:
init().then(fetchData).then(addData).catch(dberror);
function init() {
req = indexedDB.open("db", 1);
req.onupgradeneeded = e => {
var name;
var key;
console.log("Upgrading database...", e.oldVersion, e.newVersion);
db = e.currentTarget.result;
var store = db.createObjectStore("db", { keyPath: "KEY" });
db.createObjectStore("version", { keyPath: "version" });
for (name in indexes) {
key = ...
store.createIndex(name, key);
};
};
return new Promise( (resolve, reject) => {
req.onsuccess = e => {
db = e.currentTarget.result;
db.onerror = dberror;
var cursor = db.transaction("MECs").objectStore("MECs").index("STATUS_DATE").openCursor(null, 'prev');
cursor.onsuccess = e => {
if (e.target.result) {
lastMod = e.target.result.key;
fileYear = lastMod.getFullYear();
}
else lastMod = new Date(startingfileYear, 0);
resolve(lastMod);
}
cursor.onerror = reject;
};
req.onerror = e => {
dberror(e);
reject(e);
}
});
}
function fetchData(param) {
// Get data based on the param and return it
return fetchFile(filename);
}
function addData(data) {
var trans = db.transaction("db", "readwrite");
var store = trans.objectStore("db");
var req;
var n = 0;
var data2 = [];
var addPromise;
trans.onerror = event => console.log("Error! Error! ", event.target.error);
trans.onabort = event => console.log("Abort! Abort! ", event.target.error);
data.forEach((row, index) => {
//process data here
data2 = ...
});
(function storeRegData(n) {
var row = data[n];
if (!row) return;
req = store.put(row);
req.onsuccess = event => {
numUpdated++;
storeRegData(++n);
}
req.onabort = event => console.log("Abort! Abort! ", event.target.error);
req.onerror = event => console.log("Error! Error! ", event.target.error);
})(0); // I'm storing one row at a time because the transaction is failing when I queue too many rows.
addPromise = fetchData(data2).then(
response => {
var trans2 = db.transaction("db", "readwrite");
var store2 = trans2.objectStore("db");
var req2;
response.forEach(row => {
req2 = store2.put(row);
req2.onsuccess = event => numUpdated++;
req2.onerror = console.log;
});
return new Promise((resolve, reject) => trans2.oncomplete = e => resolve(response));
},
console.log)
);
return new Promise((resolve, reject) => trans.oncomplete = e => {
if (noMoreData)
resolve(addPromise);
else if (moreData)
resolve( addPromise.then(fetchData).then(addData) );
});
}
这是我的清单
{
"author": "Name",
"manifest_version": 2,
"name": "Extension",
"description": "Extension",
"version": "3.0",
"applications": {
"gecko": {
"strict_min_version": "50.0",
"id": "myID",
"update_url": "https://update.me"
}
},
"background": {
"scripts": [
"js/background.js"
]
},
"content_scripts": [
{
"matches": [ "https://match.me/*" ],
"js": [
"script.js"
],
"css": [
"style.css"
]
}
],
"icons": {
"48": "icon.png"
},
"options_ui": {
"page": "options.html"
},
"page_action": {
"browser_style": true,
"default_icon": {
"19": "icon-19.png",
"38": "icon-38.png"
},
"default_title": "Extension",
"default_popup": "popup.html"
},
"permissions": [
"https://web.address/*",
"downloads",
"notifications",
"storage",
"tabs",
"webRequest",
"webNavigation"
],
"web_accessible_resources": [
"pictures.png"
]
}
为什么当我重新启动浏览器时,Firefox 认为数据库是版本 0?下载后可以使用存储的数据,为什么每次重启都会覆盖它?我可能会做一个解决方法,我只在扩展安装或更新时创建存储和索引,但这不是实际问题的解决方案。
更新: 我尝试了以下方法无济于事 -
- 存储每个数据文件后关闭数据库并重新打开
- 为每个数据文件创建一个新的对象存储
更新 2: 看来这与存储问题有关。显然,2GB 是非持久性存储的存储限制。在 Firefox 中,您可以通过使用以下命令使存储持久化来绕过此问题:
indexedDB.open("db", { version: 1, storage: "persistent" })
查看 bugzilla 报告 here。
不幸的是,当从后台页面 运行 时,要求确认的弹出窗口没有得到处理,因此您永远无法确认。据推测,当 Firefox 56 发布时,您将能够使用 "unlimitedStorage" 权限,这将绕过确认弹出窗口,因此它应该从后台页面运行。
更新 3: 所以看起来限制实际上是 ~1.5 GB。我花了一个多星期的时间重新编写扩展程序,为每年的数据创建和使用不同的数据库,使每个数据库不超过 150 MB。当我重新启动浏览器并擦除所有数据时,onupgradeneeded
仍然执行。但是,如果我将所有数据库中的数据总量限制在上述限制内,它就可以工作。不幸的是,我仍然在同一条船上。
没有人有想法吗?
正如我在问题更新中提到的,indexedDB 的 "default" 存储似乎有 ~1.5GB 的限制。将存储更改为 "persistent" 将取消该限制。但是,由于持久存储当前需要用户输入,因此必须从可以处理 UI 响应的 window 打开数据库。
这可以通过后台脚本完成,方法是用 browser.window.create()
创建一个新的 window 并从那里打开数据库。有一些安全限制阻止了新页面中 运行 的内联脚本,所以我不得不 link 到本地 javascript 文件(即 <script src="db.js"></script>
。我想你可以还使用清单指令更改内容安全策略,但我没有那样做。
希望 unlimitedStorage
权限将在 Firefox 56 中得到支持,这将删除弹出窗口,允许持久数据库直接从 created/accessed后台脚本。
我编写了一个 Firefox WebExtension,它从网站下载数据文件并使用 IndexedDB store/update 数据。创建的 .SQLite
文件大小约为 2GB。每当我重新启动 Firefox 时,扩展都会执行 onupgradeneeded
事件,即使我总是使用版本“1”。我在那个事件中创建了数据库对象存储和索引,所以 我所有的数据最终都被删除了。
唯一没有发生的情况是当我在下载或存储数据时关闭 Firefox。 下次我启动 Firefox 时,它不会执行该事件(应该是这样)。然后它会按照编程的方式继续更新数据库。
我安装了 SQLite 管理器扩展,希望我能找出导致数据库问题的原因,但对我来说没有什么是显而易见的。
这是我的部分背景脚本:
init().then(fetchData).then(addData).catch(dberror);
function init() {
req = indexedDB.open("db", 1);
req.onupgradeneeded = e => {
var name;
var key;
console.log("Upgrading database...", e.oldVersion, e.newVersion);
db = e.currentTarget.result;
var store = db.createObjectStore("db", { keyPath: "KEY" });
db.createObjectStore("version", { keyPath: "version" });
for (name in indexes) {
key = ...
store.createIndex(name, key);
};
};
return new Promise( (resolve, reject) => {
req.onsuccess = e => {
db = e.currentTarget.result;
db.onerror = dberror;
var cursor = db.transaction("MECs").objectStore("MECs").index("STATUS_DATE").openCursor(null, 'prev');
cursor.onsuccess = e => {
if (e.target.result) {
lastMod = e.target.result.key;
fileYear = lastMod.getFullYear();
}
else lastMod = new Date(startingfileYear, 0);
resolve(lastMod);
}
cursor.onerror = reject;
};
req.onerror = e => {
dberror(e);
reject(e);
}
});
}
function fetchData(param) {
// Get data based on the param and return it
return fetchFile(filename);
}
function addData(data) {
var trans = db.transaction("db", "readwrite");
var store = trans.objectStore("db");
var req;
var n = 0;
var data2 = [];
var addPromise;
trans.onerror = event => console.log("Error! Error! ", event.target.error);
trans.onabort = event => console.log("Abort! Abort! ", event.target.error);
data.forEach((row, index) => {
//process data here
data2 = ...
});
(function storeRegData(n) {
var row = data[n];
if (!row) return;
req = store.put(row);
req.onsuccess = event => {
numUpdated++;
storeRegData(++n);
}
req.onabort = event => console.log("Abort! Abort! ", event.target.error);
req.onerror = event => console.log("Error! Error! ", event.target.error);
})(0); // I'm storing one row at a time because the transaction is failing when I queue too many rows.
addPromise = fetchData(data2).then(
response => {
var trans2 = db.transaction("db", "readwrite");
var store2 = trans2.objectStore("db");
var req2;
response.forEach(row => {
req2 = store2.put(row);
req2.onsuccess = event => numUpdated++;
req2.onerror = console.log;
});
return new Promise((resolve, reject) => trans2.oncomplete = e => resolve(response));
},
console.log)
);
return new Promise((resolve, reject) => trans.oncomplete = e => {
if (noMoreData)
resolve(addPromise);
else if (moreData)
resolve( addPromise.then(fetchData).then(addData) );
});
}
这是我的清单
{
"author": "Name",
"manifest_version": 2,
"name": "Extension",
"description": "Extension",
"version": "3.0",
"applications": {
"gecko": {
"strict_min_version": "50.0",
"id": "myID",
"update_url": "https://update.me"
}
},
"background": {
"scripts": [
"js/background.js"
]
},
"content_scripts": [
{
"matches": [ "https://match.me/*" ],
"js": [
"script.js"
],
"css": [
"style.css"
]
}
],
"icons": {
"48": "icon.png"
},
"options_ui": {
"page": "options.html"
},
"page_action": {
"browser_style": true,
"default_icon": {
"19": "icon-19.png",
"38": "icon-38.png"
},
"default_title": "Extension",
"default_popup": "popup.html"
},
"permissions": [
"https://web.address/*",
"downloads",
"notifications",
"storage",
"tabs",
"webRequest",
"webNavigation"
],
"web_accessible_resources": [
"pictures.png"
]
}
为什么当我重新启动浏览器时,Firefox 认为数据库是版本 0?下载后可以使用存储的数据,为什么每次重启都会覆盖它?我可能会做一个解决方法,我只在扩展安装或更新时创建存储和索引,但这不是实际问题的解决方案。
更新: 我尝试了以下方法无济于事 -
- 存储每个数据文件后关闭数据库并重新打开
- 为每个数据文件创建一个新的对象存储
更新 2: 看来这与存储问题有关。显然,2GB 是非持久性存储的存储限制。在 Firefox 中,您可以通过使用以下命令使存储持久化来绕过此问题:
indexedDB.open("db", { version: 1, storage: "persistent" })
查看 bugzilla 报告 here。
不幸的是,当从后台页面 运行 时,要求确认的弹出窗口没有得到处理,因此您永远无法确认。据推测,当 Firefox 56 发布时,您将能够使用 "unlimitedStorage" 权限,这将绕过确认弹出窗口,因此它应该从后台页面运行。
更新 3: 所以看起来限制实际上是 ~1.5 GB。我花了一个多星期的时间重新编写扩展程序,为每年的数据创建和使用不同的数据库,使每个数据库不超过 150 MB。当我重新启动浏览器并擦除所有数据时,onupgradeneeded
仍然执行。但是,如果我将所有数据库中的数据总量限制在上述限制内,它就可以工作。不幸的是,我仍然在同一条船上。
没有人有想法吗?
正如我在问题更新中提到的,indexedDB 的 "default" 存储似乎有 ~1.5GB 的限制。将存储更改为 "persistent" 将取消该限制。但是,由于持久存储当前需要用户输入,因此必须从可以处理 UI 响应的 window 打开数据库。
这可以通过后台脚本完成,方法是用 browser.window.create()
创建一个新的 window 并从那里打开数据库。有一些安全限制阻止了新页面中 运行 的内联脚本,所以我不得不 link 到本地 javascript 文件(即 <script src="db.js"></script>
。我想你可以还使用清单指令更改内容安全策略,但我没有那样做。
希望 unlimitedStorage
权限将在 Firefox 56 中得到支持,这将删除弹出窗口,允许持久数据库直接从 created/accessed后台脚本。