Skip to content

Commit

Permalink
fix(offline): Speed up offline storage by ~87%
Browse files Browse the repository at this point in the history
  • Loading branch information
joeyparrish committed Apr 29, 2022
1 parent 73f6de3 commit a696bea
Showing 1 changed file with 40 additions and 34 deletions.
74 changes: 40 additions & 34 deletions lib/offline/storage.js
Expand Up @@ -196,7 +196,7 @@ shaka.offline.Storage = class {
goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');

goog.asserts.assert(
this.config_, 'Cannot reconfigure stroage after calling destroy.');
this.config_, 'Cannot reconfigure storage after calling destroy.');
return shaka.util.PlayerConfiguration.mergeConfigObjects(
/* destination= */ this.config_, /* updates= */ config );
}
Expand Down Expand Up @@ -441,36 +441,34 @@ shaka.offline.Storage = class {
async downloadSegments_(
toDownload, manifestId, manifestDB, downloader, config, storage,
manifest, drmEngine) {
const pendingManifestUpdates = {};
let pendingDataSize = 0;

/**
* @param {!Array.<!shaka.offline.DownloadInfo>} toDownload
* @param {boolean} updateDRM
*/
const download = async (toDownload, updateDRM) => {
const throwIfAbortedFn = () => {
this.ensureNotDestroyed_();
};
for (const download of toDownload) {
/** @param {?BufferSource} data */
let data;
const request = download.makeSegmentRequest(config);
const estimateId = download.estimateId;
const isInitSegment = download.isInitSegment;
const onDownloaded = (d) => {
data = d;
return Promise.resolve();
};
downloader.queue(download.groupId,
request, estimateId, isInitSegment, onDownloaded);
downloader.queueWork(download.groupId, async () => {
goog.asserts.assert(data, 'We should have loaded data by now');
goog.asserts.assert(data instanceof ArrayBuffer,
'The data should be an ArrayBuffer');

const onDownloaded = async (data) => {
// Store the data.
const dataKeys = await storage.addSegments([{data}]);
this.ensureNotDestroyed_();

// Store the necessary update to the manifest, to be processed later.
const ref = /** @type {!shaka.media.SegmentReference} */ (
download.ref);
manifestDB = (await shaka.offline.Storage.assignStreamToManifest(
manifestId, ref, {data}, throwIfAbortedFn)) || manifestDB;
});
const id = shaka.offline.DownloadInfo.idForSegmentRef(ref);
pendingManifestUpdates[id] = dataKeys[0];
pendingDataSize += data.byteLength;
};

downloader.queue(download.groupId,
request, estimateId, isInitSegment, onDownloaded);
}
await downloader.waitToFinish();

Expand Down Expand Up @@ -502,6 +500,13 @@ shaka.offline.Storage = class {
await download(toDownload, false);
this.ensureNotDestroyed_();

const newManifestDB =
await shaka.offline.Storage.assignStreamToManifest(
manifestId, pendingManifestUpdates, pendingDataSize,
() => this.ensureNotDestroyed_());
manifestDB = newManifestDB || manifestDB;
this.ensureNotDestroyed_();

goog.asserts.assert(
!manifestDB.isIncomplete, 'The manifest should be complete by now');
} else {
Expand Down Expand Up @@ -538,19 +543,18 @@ shaka.offline.Storage = class {
* changes of the other.
*
* @param {number} manifestId
* @param {!shaka.media.SegmentReference} ref
* @param {shaka.extern.SegmentDataDB} data
* @param {!Object.<string, number>} manifestUpdates
* @param {number} dataSizeUpdate
* @param {function()} throwIfAbortedFn A function that should throw if the
* download has been aborted.
* @return {!Promise.<?shaka.extern.ManifestDB>}
*/
static async assignStreamToManifest(manifestId, ref, data, throwIfAbortedFn) {
static async assignStreamToManifest(
manifestId, manifestUpdates, dataSizeUpdate, throwIfAbortedFn) {
/** @type {shaka.offline.StorageMuxer} */
const muxer = new shaka.offline.StorageMuxer();

const idForRef = shaka.offline.DownloadInfo.idForSegmentRef(ref);
let manifestUpdated = false;
let dataKey;
let activeHandle;
/** @type {!shaka.extern.ManifestDB} */
let manifestDB;
Expand All @@ -561,11 +565,6 @@ shaka.offline.Storage = class {
await muxer.init();
activeHandle = await muxer.getActive();

// Store the data.
const dataKeys = await activeHandle.cell.addSegments([data]);
dataKey = dataKeys[0];
throwIfAbortedFn();

// Acquire the mutex before accessing the manifest, since there could be
// multiple instances of this method running at once.
mutexId = await shaka.offline.Storage.mutex_.acquire();
Expand All @@ -580,19 +579,25 @@ shaka.offline.Storage = class {
let complete = true;
for (const stream of manifestDB.streams) {
for (const segment of stream.segments) {
if (segment.pendingSegmentRefId == idForRef) {
let dataKey = segment.pendingSegmentRefId ?
manifestUpdates[segment.pendingSegmentRefId] : null;
if (dataKey != null) {
segment.dataKey = dataKey;
// Now that the segment has been associated with the appropriate
// dataKey, the pendingSegmentRefId is no longer necessary.
segment.pendingSegmentRefId = undefined;
}
if (segment.pendingInitSegmentRefId == idForRef) {

dataKey = segment.pendingInitSegmentRefId ?
manifestUpdates[segment.pendingInitSegmentRefId] : null;
if (dataKey != null) {
segment.initSegmentKey = dataKey;
// Now that the init segment has been associated with the
// appropriate initSegmentKey, the pendingInitSegmentRefId is no
// longer necessary.
segment.pendingInitSegmentRefId = undefined;
}

if (segment.pendingSegmentRefId) {
complete = false;
}
Expand All @@ -603,7 +608,7 @@ shaka.offline.Storage = class {
}

// Update the size of the manifest.
manifestDB.size += data.data.byteLength;
manifestDB.size += dataSizeUpdate;

// Mark the manifest as complete, if all segments are downloaded.
if (complete) {
Expand All @@ -617,11 +622,12 @@ shaka.offline.Storage = class {
} catch (e) {
await shaka.offline.Storage.cleanStoredManifest(manifestId);

if (activeHandle && !manifestUpdated && dataKey) {
if (activeHandle && !manifestUpdated) {
const dataKeys = Object.values(manifestUpdates);
// The cleanStoredManifest method will not "see" any segments that have
// been downloaded but not assigned to the manifest yet. So un-store
// them separately.
await activeHandle.cell.removeSegments([dataKey], (key) => {});
await activeHandle.cell.removeSegments(dataKeys, (key) => {});
}

throw e;
Expand Down

0 comments on commit a696bea

Please sign in to comment.