mirror of
https://github.com/kiwix/kiwix-js-pwa.git
synced 2025-09-10 04:40:27 -04:00
New non-parallel decompression code
Former-commit-id: 8f450fb19ac82d74c3b4bce9580976ddfce6a888 [formerly 5df60d1c810c7b98316e7a1ba5e0133cef329d25] Former-commit-id: 275e5245e40972f2bb4ae1ce3a6ed34389497421
This commit is contained in:
parent
4f7e3fd4a5
commit
19293b062d
@ -24,6 +24,18 @@ define(['q'], function(q) {
|
|||||||
var xzdec = Module; //@todo including via requirejs seems to not work
|
var xzdec = Module; //@todo including via requirejs seems to not work
|
||||||
xzdec._init();
|
xzdec._init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of milliseconds to wait for the decompressor to be available for another chunk
|
||||||
|
* @type Integer
|
||||||
|
*/
|
||||||
|
var DELAY_WAITING_IDLE_DECOMPRESSOR = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the decompressor already working?
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
var busy = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef Decompressor
|
* @typedef Decompressor
|
||||||
* @property {Integer} _chunkSize
|
* @property {Integer} _chunkSize
|
||||||
@ -51,6 +63,7 @@ define(['q'], function(q) {
|
|||||||
* @param {Integer} length
|
* @param {Integer} length
|
||||||
*/
|
*/
|
||||||
Decompressor.prototype.readSlice = function(offset, length) {
|
Decompressor.prototype.readSlice = function(offset, length) {
|
||||||
|
busy = true;
|
||||||
var that = this;
|
var that = this;
|
||||||
this._inStreamPos = 0;
|
this._inStreamPos = 0;
|
||||||
this._outStreamPos = 0;
|
this._outStreamPos = 0;
|
||||||
@ -59,10 +72,40 @@ define(['q'], function(q) {
|
|||||||
this._outBufferPos = 0;
|
this._outBufferPos = 0;
|
||||||
return this._readLoop(offset, length).then(function(data) {
|
return this._readLoop(offset, length).then(function(data) {
|
||||||
xzdec._release(that._decHandle);
|
xzdec._release(that._decHandle);
|
||||||
|
busy = false;
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read length bytes, offset into the decompressed stream.
|
||||||
|
* This function ensures that only one decompression runs at a time.
|
||||||
|
*
|
||||||
|
* @param {Integer} offset
|
||||||
|
* @param {Integer} length
|
||||||
|
*/
|
||||||
|
Decompressor.prototype.readSliceSingleThread = function(offset, length) {
|
||||||
|
if (!busy) {
|
||||||
|
//console.log("decompressor not busy : let's read the slice " + offset + " " + length);
|
||||||
|
return this.readSlice(offset, length);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//console.log("decompressor busy : let's wait before reading the slice " + offset + " " + length);
|
||||||
|
// The decompressor is already in progress.
|
||||||
|
// To avoid using too much memory, we wait until it has finished
|
||||||
|
// before using it for another decompression.
|
||||||
|
// Inspired by https://codereview.stackexchange.com/questions/145563/angularjs-recursive-function-call-with-timeout
|
||||||
|
var that = this;
|
||||||
|
var deferred = q.defer();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
that.readSliceSingleThread(offset, length).then(deferred.resolve, deferred.reject);
|
||||||
|
}, DELAY_WAITING_IDLE_DECOMPRESSOR);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Integer} offset
|
* @param {Integer} offset
|
||||||
|
@ -23,13 +23,6 @@
|
|||||||
define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
||||||
function(zimfile, zimDirEntry, util, utf8) {
|
function(zimfile, zimDirEntry, util, utf8) {
|
||||||
|
|
||||||
// DEV: This controls the number of jobs sent to the decompressor at any one time. The value should be set in
|
|
||||||
// init.js and will need fine-turning according to your build of xzdec, and the memory constraints of your target
|
|
||||||
// environment(s). Some low-end mobiles can only support a value of 1.
|
|
||||||
var MAX_DECOMPRESSOR_JOBS = params.xzMaxJobs || 4;
|
|
||||||
// Counter to track the number of decompression-type jobs sent to xz
|
|
||||||
var xzJobs = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZIM Archive
|
* ZIM Archive
|
||||||
*
|
*
|
||||||
@ -222,22 +215,6 @@ define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
|||||||
this._file.dirEntryByUrlIndex(dirEntry.redirectTarget).then(callback);
|
this._file.dirEntryByUrlIndex(dirEntry.redirectTarget).then(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility queue and store for dirEntries awaiting the decompressor
|
|
||||||
* See head of file for information about MAX_DECOMPRESSOR_JOBS
|
|
||||||
*
|
|
||||||
* @param {DirEntry} dirEntry A directory entry to queue
|
|
||||||
* @param {callbackDirEntry} callback The function to call when the decompressor is freed up
|
|
||||||
* @returns {callback} Resumes the calling function
|
|
||||||
*/
|
|
||||||
function xzAwait (dirEntry, callback) {
|
|
||||||
if (xzJobs < MAX_DECOMPRESSOR_JOBS) {
|
|
||||||
return callback(dirEntry);
|
|
||||||
} else {
|
|
||||||
setTimeout(xzAwait, 100, dirEntry, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @callback callbackStringContent
|
* @callback callbackStringContent
|
||||||
* @param {String} content String content
|
* @param {String} content String content
|
||||||
@ -249,13 +226,9 @@ define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
|||||||
* @param {callbackStringContent} callback
|
* @param {callbackStringContent} callback
|
||||||
*/
|
*/
|
||||||
ZIMArchive.prototype.readUtf8File = function(dirEntry, callback) {
|
ZIMArchive.prototype.readUtf8File = function(dirEntry, callback) {
|
||||||
xzAwait(dirEntry, function(dirEntry) {
|
dirEntry.readData().then(function(data) {
|
||||||
xzJobs++;
|
|
||||||
return dirEntry.readData().then(function(data) {
|
|
||||||
xzJobs--;
|
|
||||||
callback(dirEntry, utf8.parse(data));
|
callback(dirEntry, utf8.parse(data));
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -269,19 +242,9 @@ define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
|||||||
* @param {callbackBinaryContent} callback
|
* @param {callbackBinaryContent} callback
|
||||||
*/
|
*/
|
||||||
ZIMArchive.prototype.readBinaryFile = function(dirEntry, callback) {
|
ZIMArchive.prototype.readBinaryFile = function(dirEntry, callback) {
|
||||||
if (/\.svg$|\.css$/i.test(dirEntry.url)) {
|
|
||||||
xzAwait(dirEntry, function(dirEntry) {
|
|
||||||
xzJobs++;
|
|
||||||
return dirEntry.readData().then(function(data) {
|
|
||||||
xzJobs--;
|
|
||||||
callback(dirEntry, data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return dirEntry.readData().then(function(data) {
|
return dirEntry.readData().then(function(data) {
|
||||||
callback(dirEntry, data);
|
callback(dirEntry, data);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +97,7 @@ define(['xzdec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry'], function(xz, util,
|
|||||||
return readRequests[0];
|
return readRequests[0];
|
||||||
} else {
|
} else {
|
||||||
// Wait until all are resolved and concatenate.
|
// Wait until all are resolved and concatenate.
|
||||||
console.log("Concatenating split ZIM fileset...");
|
console.log("CONCAT");
|
||||||
return Q.all(readRequests).then(function(arrays) {
|
return Q.all(readRequests).then(function(arrays) {
|
||||||
var concatenated = new Uint8Array(size);
|
var concatenated = new Uint8Array(size);
|
||||||
var sizeSum = 0;
|
var sizeSum = 0;
|
||||||
@ -193,16 +193,16 @@ define(['xzdec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry'], function(xz, util,
|
|||||||
};
|
};
|
||||||
if (compressionType[0] === 0 || compressionType[0] === 1) {
|
if (compressionType[0] === 0 || compressionType[0] === 1) {
|
||||||
// uncompressed
|
// uncompressed
|
||||||
decompressor = { readSlice: plainBlobReader };
|
decompressor = { readSliceSingleThread: plainBlobReader };
|
||||||
} else if (compressionType[0] === 4) {
|
} else if (compressionType[0] === 4) {
|
||||||
decompressor = new xz.Decompressor(plainBlobReader);
|
decompressor = new xz.Decompressor(plainBlobReader);
|
||||||
} else {
|
} else {
|
||||||
return new Uint8Array(); // unsupported compression type
|
return new Uint8Array(); // unsupported compression type
|
||||||
}
|
}
|
||||||
return decompressor.readSlice(blob * 4, 8).then(function(data) {
|
return decompressor.readSliceSingleThread(blob * 4, 8).then(function(data) {
|
||||||
var blobOffset = readInt(data, 0, 4);
|
var blobOffset = readInt(data, 0, 4);
|
||||||
var nextBlobOffset = readInt(data, 4, 4);
|
var nextBlobOffset = readInt(data, 4, 4);
|
||||||
return decompressor.readSlice(blobOffset, nextBlobOffset - blobOffset);
|
return decompressor.readSliceSingleThread(blobOffset, nextBlobOffset - blobOffset);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user