1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-23 16:25:22 +03:00

FirmwareCache: memory footprint and UI improvements

This commit is contained in:
Kiripolszky Károly 2018-05-02 14:47:41 +02:00
parent caef8dbf3c
commit 54bdd2da14
2 changed files with 105 additions and 59 deletions

View file

@ -24,16 +24,19 @@
/** /**
* @typedef {object} CacheItem * @typedef {object} CacheItem
* @property {Descriptor} release * @property {Descriptor} release
* @property {string} [hexdata] * @property {string} hexdata
*/ */
/** /**
* Manages caching of downloaded firmware files * Manages caching of downloaded firmware files
*/ */
let FirmwareCache = (function() { let FirmwareCache = (function () {
let MetadataStorage = (function() { let onPutToCacheCallback,
let CACHEKEY = "firmware-cache-metadata"; onRemoveFromCacheCallback;
let JournalStorage = (function () {
let CACHEKEY = "firmware-cache-journal";
/** /**
* @param {Array} data LRU key-value pairs * @param {Array} data LRU key-value pairs
@ -62,25 +65,33 @@ let FirmwareCache = (function() {
}; };
})(); })();
let metadataCache = new LRUMap(100); let journal = new LRUMap(100),
let metadataLoaded = false; journalLoaded = false;
metadataCache.shift = function() { journal.shift = function () {
// remove hexdata for oldest release // remove cached data for oldest release
let oldest = LRUMap.prototype.shift.call(this); let oldest = LRUMap.prototype.shift.call(this);
if (oldest !== undefined) { if (oldest === undefined) {
/** @type {CacheItem} */ return undefined;
let cached = oldest[1];
let hexdataKey = withHexdataPrefix(keyOf(cached.release));
chrome.storage.local.remove(hexdataKey,
() => console.debug("Hex data removed: " + hexdataKey));
} }
let key = oldest[0];
let cacheKey = withCachePrefix(key);
chrome.storage.local.get(cacheKey, obj => {
/** @type {CacheItem} */
let cached = typeof obj === "object" && obj.hasOwnProperty(cacheKey)
? obj[cacheKey]
: null;
chrome.storage.local.remove(cacheKey, () => {
onRemoveFromCache(cached.release);
console.debug("Cache data removed: " + cacheKey);
});
});
return oldest; return oldest;
}; };
/** /**
* @param {Descriptor} release * @param {Descriptor} release
* @returns {string} A key used for caching the metadata for a release * @returns {string} A key used to store a release in the journal
*/ */
function keyOf(release) { function keyOf(release) {
return release.file; return release.file;
@ -88,10 +99,10 @@ let FirmwareCache = (function() {
/** /**
* @param {string} key * @param {string} key
* @returns {string} A key for storing the hex data for a release * @returns {string} A key for storing cached data for a release
*/ */
function withHexdataPrefix(key) { function withCachePrefix(key) {
return "hex:" + key; return "cache:" + key;
} }
/** /**
@ -99,11 +110,11 @@ let FirmwareCache = (function() {
* @returns {boolean} * @returns {boolean}
*/ */
function has(release) { function has(release) {
if (!metadataLoaded) { if (!journalLoaded) {
console.warn("Cache not yet loaded"); console.warn("Cache not yet loaded");
return false; return false;
} }
return metadataCache.has(keyOf(release)); return journal.has(keyOf(release));
} }
/** /**
@ -111,48 +122,68 @@ let FirmwareCache = (function() {
* @param {string} hexdata * @param {string} hexdata
*/ */
function put(release, hexdata) { function put(release, hexdata) {
if (!metadataLoaded) { if (!journalLoaded) {
console.warn("Cache not yet loaded"); console.warn("Cache journal not yet loaded");
return;
}
if (has(release)) {
console.debug("Firmware is already cached: " + keyOf(release));
return; return;
} }
let key = keyOf(release); let key = keyOf(release);
let hexdataKey = withHexdataPrefix(key); if (has(release)) {
metadataCache.set(key, { console.debug("Firmware is already cached: " + key);
release: release, return;
}); }
MetadataStorage.persist(metadataCache.toJSON()); journal.set(key, true);
JournalStorage.persist(journal.toJSON());
let obj = {}; let obj = {};
obj[hexdataKey] = hexdata; obj[withCachePrefix(key)] = {
chrome.storage.local.set(obj); release: release,
hexdata: hexdata,
};
chrome.storage.local.set(obj, () => {
console.info("Release put to cache: " + key);
onPutToCache(release);
});
} }
/** /**
* @param {Descriptor} release * @param {Descriptor} release
* @param {Function} callback * @param {Function} callback
* @returns {(CacheItem|undefined)}
*/ */
function get(release, callback) { function get(release, callback) {
if (!metadataLoaded) { if (!journalLoaded) {
console.warn("Cache not yet loaded"); console.warn("Cache journal not yet loaded");
return undefined; return undefined;
} }
let key = keyOf(release); let key = keyOf(release);
/** @type {CacheItem} */ if (!has(release)) {
let cached = metadataCache.get(key); console.debug("Firmware is not cached: " + key);
if (cached !== undefined) { return;
let hexdataKey = withHexdataPrefix(key); }
chrome.storage.local.get(hexdataKey, function(obj) { let cacheKey = withCachePrefix(key);
cached.hexdata = typeof obj === "object" && obj.hasOwnProperty(hexdataKey) chrome.storage.local.get(cacheKey, obj => {
? obj[hexdataKey] /** @type {CacheItem} */
: null; let cached = typeof obj === "object" && obj.hasOwnProperty(cacheKey)
callback(cached); ? obj[cacheKey]
}); : null;
callback(cached);
});
}
/**
* @param {Descriptor} release
*/
function onPutToCache(release) {
if (typeof onPutToCacheCallback === "function") {
onPutToCacheCallback(release);
}
}
/**
* @param {Descriptor} release
*/
function onRemoveFromCache(release) {
if (typeof onRemoveFromCacheCallback === "function") {
onRemoveFromCacheCallback(release);
} }
return cached;
} }
/** /**
@ -163,21 +194,23 @@ let FirmwareCache = (function() {
for (let entry of entries) { for (let entry of entries) {
pairs.push([entry.key, entry.value]); pairs.push([entry.key, entry.value]);
} }
metadataCache.assign(pairs); journal.assign(pairs);
metadataLoaded = true; journalLoaded = true;
console.info("Firmware cache loaded; number of entries: " + entries.length); console.info("Firmware cache journal loaded; number of entries: " + entries.length);
} }
return { return {
has: has, has: has,
put: put, put: put,
get: get, get: get,
onPutToCache: callback => onPutToCacheCallback = callback,
onRemoveFromCache: callback => onRemoveFromCacheCallback = callback,
load: () => { load: () => {
MetadataStorage.load(onEntriesLoaded); JournalStorage.load(onEntriesLoaded);
}, },
flush: () => { flush: () => {
MetadataStorage.persist(metadataCache.toJSON()); JournalStorage.persist(journal.toJSON());
metadataCache.clear(); journal.clear();
}, },
}; };
})(); })();

View file

@ -16,8 +16,22 @@ TABS.firmware_flasher.initialize = function (callback) {
var intel_hex = false, // standard intel hex in string format var intel_hex = false, // standard intel hex in string format
parsed_hex = false; // parsed raw hex in array format parsed_hex = false; // parsed raw hex in array format
/**
* Change boldness of firmware option depending on cache status
*
* @param {Descriptor} release
*/
function onFirmwareCacheUpdate(release) {
$("option[value='{0}']".format(release.version))
.css("font-weight", FirmwareCache.has(release)
? "bold"
: "normal");
}
$('#content').load("./tabs/firmware_flasher.html", function () { $('#content').load("./tabs/firmware_flasher.html", function () {
FirmwareCache.load(); FirmwareCache.load();
FirmwareCache.onPutToCache(onFirmwareCacheUpdate);
FirmwareCache.onRemoveFromCache(onFirmwareCacheUpdate);
function parse_hex(str, callback) { function parse_hex(str, callback) {
// parsing hex in different thread // parsing hex in different thread
@ -41,7 +55,6 @@ TABS.firmware_flasher.initialize = function (callback) {
if (parsed_hex) { if (parsed_hex) {
if (!FirmwareCache.has(summary)) { if (!FirmwareCache.has(summary)) {
FirmwareCache.put(summary, intel_hex); FirmwareCache.put(summary, intel_hex);
console.info("Release put to cache: " + summary.file);
} }
var url; var url;
@ -213,7 +226,7 @@ TABS.firmware_flasher.initialize = function (callback) {
)) ))
.css("font-weight", FirmwareCache.has(descriptor) .css("font-weight", FirmwareCache.has(descriptor)
? "bold" ? "bold"
: null : "normal"
) )
.data('summary', descriptor); .data('summary', descriptor);