Created
April 17, 2024 05:22
-
-
Save shadow-light/e00da7bf774f343917627b72a03e075c to your computer and use it in GitHub Desktop.
Electron IndexedDB corruption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"> | |
<link href="./styles.css" rel="stylesheet"> | |
<title>IndexedDB disk space test</title> | |
</head> | |
<body> | |
<h2>Versions</h2> | |
Node.js <span id="node-version"></span>, | |
Chromium <span id="chrome-version"></span>, | |
and Electron <span id="electron-version"></span>. | |
<h2>Add MB to database</h2> | |
<div> | |
<input type='number' class='amount' value='10' /> | |
<button class='add'>Add</button> | |
</div> | |
<h2>Stats</h2> | |
<table> | |
<tr> | |
<th>Real disk space</th> | |
<td>(accessible to OS)</td> | |
</tr> | |
<tr> | |
<td>Total</td> | |
<td class='real_total'></td> | |
</tr> | |
<tr> | |
<td>Used</td> | |
<td class='real_used'></td> | |
</tr> | |
<tr> | |
<td>Remaining</td> | |
<td class='real_remaining'></td> | |
</tr> | |
</table> | |
<table> | |
<tr> | |
<th>Browser disk space</th> | |
<td>(accessible to Chromium)</td> | |
</tr> | |
<tr> | |
<td>Total</td> | |
<td class='browser_total'></td> | |
</tr> | |
<tr> | |
<td>Used</td> | |
<td class='browser_used'></td> | |
</tr> | |
<tr> | |
<td>Remaining</td> | |
<td class='browser_remaining'></td> | |
</tr> | |
</table> | |
<script src="./renderer.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* IndexedDB may get wipped if storage limit reached | |
This test must be run with Electron set to save data in a disk with little space left | |
Linux guide to creating a small virtual disk: https://stackoverflow.com/questions/16044204/testing-out-of-disk-space-in-linux | |
1. Set path below to a disk with little space (e.g. 100 MB) | |
[Repeat next steps several times while observing IndexedDB in dev tools] | |
2. Rapidly click the add button beyond the storage's limit | |
3. Close and reopen the app | |
4. Keep repeating until IndexedDB gets reset and the following error appears in Electron's console: | |
[7451:0417/145053.223225:ERROR:indexed_db_bucket_context.cc(338)] Failed to open LevelDB database from /.../IndexedDB/file__0.indexeddb.leveldb,Corruption: checksum mismatch | |
[7451:0417/145053.601039:ERROR:indexed_db_bucket_context.cc(1501)] IndexedDB recovering from a corrupted (and deleted) database. | |
*/ | |
const { app, BrowserWindow, ipcMain } = require('electron') | |
const check_disk_space = require('check-disk-space') | |
const path = require('node:path') | |
// TODO Set this to a virtual disk with e.g. 100 MB free | |
app.setPath('userData', '/tmp/my_disk') | |
// Function for creating window | |
function createWindow () { | |
const mainWindow = new BrowserWindow({ | |
width: 800, | |
height: 600, | |
webPreferences: { | |
preload: path.join(__dirname, 'preload.js') | |
} | |
}) | |
mainWindow.loadFile('index.html') | |
mainWindow.webContents.openDevTools() | |
} | |
// Create window | |
app.whenReady().then(() => { | |
createWindow() | |
app.on('activate', function () { | |
if (BrowserWindow.getAllWindows().length === 0) createWindow() | |
}) | |
}) | |
app.on('window-all-closed', function () { | |
if (process.platform !== 'darwin') app.quit() | |
}) | |
// Provide browser with real disk space stats when it asks (for the disk used for user data) | |
ipcMain.handle('space', async event => { | |
return check_disk_space.default(app.getPath('userData')) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "innate-brass-flood-7hli6", | |
"productName": "innate-brass-flood-7hli6", | |
"description": "My Electron application description", | |
"keywords": [], | |
"main": "./main.js", | |
"version": "1.0.0", | |
"author": "me", | |
"scripts": { | |
"start": "electron ." | |
}, | |
"dependencies": { | |
"check-disk-space": "3.4.0" | |
}, | |
"devDependencies": { | |
"electron": "30.0.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {ipcRenderer, contextBridge} = require('electron') | |
window.addEventListener('DOMContentLoaded', () => { | |
const replaceText = (selector, text) => { | |
const element = document.getElementById(selector) | |
if (element) element.innerText = text | |
} | |
for (const type of ['chrome', 'node', 'electron']) { | |
replaceText(`${type}-version`, process.versions[type]) | |
} | |
}) | |
// Method for asking OS what real disk space is | |
contextBridge.exposeInMainWorld('electronAPI', { | |
check_disk_space: async () => { | |
return ipcRenderer.invoke('space') | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create db | |
const open_db = indexedDB.open('test', 1) | |
open_db.onupgradeneeded = (event) => { | |
event.target.result.createObjectStore("store", {autoIncrement: true}) | |
} | |
// Utils | |
const amb = 1024 * 1024 | |
const to_mb_str = bytes => parseInt(bytes / amb).toLocaleString() | |
const percent = (portion, total) => (portion / total * 100).toLocaleString() + '%' | |
// Update storage stats | |
async function update_stats (){ | |
// Get real disk space | |
const real = await window.electronAPI.check_disk_space() | |
// Get browser space (total is app's usage + remaining) | |
const browser = await navigator.storage.estimate() | |
// Update real values | |
document.querySelector('.real_total').textContent = to_mb_str(real.size) | |
const real_used = real.size - real.free | |
document.querySelector('.real_used').textContent = | |
to_mb_str(real_used) + ` (${percent(real_used, real.size)})` | |
document.querySelector('.real_remaining').textContent = | |
to_mb_str(real.free) + ` (${percent(real.free, real.size)})` | |
// Update browser values | |
document.querySelector('.browser_total').textContent = to_mb_str(browser.quota) | |
document.querySelector('.browser_used').textContent = | |
to_mb_str(browser.usage) + ` (${percent(browser.usage, browser.quota)})` | |
const browser_remaining = browser.quota - browser.usage | |
document.querySelector('.browser_remaining').textContent = | |
to_mb_str(browser_remaining) + ` (${percent(browser_remaining, browser.quota)})` | |
} | |
// Initial update | |
update_stats() | |
// Handle addition of data | |
document.querySelector('.add').addEventListener('click', () => { | |
// Generate the data and add it to the database | |
const mb = parseInt(document.querySelector('.amount').value) | |
const data = new ArrayBuffer(mb * amb) | |
open_db.result.transaction('store', 'readwrite').objectStore('store').add(data) | |
// Check disk space after a delay so new addition affects it | |
setTimeout(update_stats, 1000) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
max-width: 600px; | |
margin: 50px auto; | |
font-family: monospace; | |
} | |
h2, table { | |
margin: 48px 0 24px 0; | |
} | |
th, td { | |
padding: 6px 24px 6px 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment