Skip to content

Commit

Permalink
Fix race condition in VectorTileWorkerSource#reloadTile
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Mar 14, 2018
1 parent 3eaea8e commit b42a665
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 13 deletions.
24 changes: 11 additions & 13 deletions src/source/vector_tile_worker_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,22 +147,20 @@ class VectorTileWorkerSource implements WorkerSource {
const workerTile = loaded[uid];
workerTile.showCollisionBoxes = params.showCollisionBoxes;

const done = (err, data) => {
const reloadCallback = workerTile.reloadCallback;
if (reloadCallback) {
delete workerTile.reloadCallback;
workerTile.parse(workerTile.vectorTile, vtSource.layerIndex, vtSource.actor, reloadCallback);
}
callback(err, data);
};

if (workerTile.status === 'parsing') {
workerTile.reloadCallback = callback;
workerTile.reloadCallback = done;
} else if (workerTile.status === 'done') {
workerTile.parse(workerTile.vectorTile, this.layerIndex, this.actor, done.bind(workerTile));
}

}

function done(err, data) {
if (this.reloadCallback) {
const reloadCallback = this.reloadCallback;
delete this.reloadCallback;
this.parse(this.vectorTile, vtSource.layerIndex, vtSource.actor, reloadCallback);
workerTile.parse(workerTile.vectorTile, this.layerIndex, this.actor, done);
}

callback(err, data);
}
}

Expand Down
101 changes: 101 additions & 0 deletions test/unit/source/vector_tile_worker_source.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,107 @@ test('VectorTileWorkerSource#removeTile removes loaded tile', (t) => {
t.end();
});

test('VectorTileWorkerSource#reloadTile reloads a previously-loaded tile', (t) => {
const source = new VectorTileWorkerSource(null, new StyleLayerIndex());
const parse = t.spy();

source.loaded = {
'0': {
status: 'done',
parse
}
};

const callback = t.spy();
source.reloadTile({ uid: 0 }, callback);
t.equal(parse.callCount, 1);

parse.firstCall.args[3]();
t.equal(callback.callCount, 1);

t.end();
});

test('VectorTileWorkerSource#reloadTile queues a reload when parsing is in progress', (t) => {
const source = new VectorTileWorkerSource(null, new StyleLayerIndex());
const parse = t.spy();

source.loaded = {
'0': {
status: 'done',
parse
}
};

const callback1 = t.spy();
const callback2 = t.spy();
source.reloadTile({ uid: 0 }, callback1);
t.equal(parse.callCount, 1);

source.loaded[0].status = 'parsing';
source.reloadTile({ uid: 0 }, callback2);
t.equal(parse.callCount, 1);

parse.firstCall.args[3]();
t.equal(parse.callCount, 2);
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 0);

parse.secondCall.args[3]();
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 1);

t.end();
});

test('VectorTileWorkerSource#reloadTile handles multiple pending reloads', (t) => {
// https://github.com/mapbox/mapbox-gl-js/issues/6308
const source = new VectorTileWorkerSource(null, new StyleLayerIndex());
const parse = t.spy();

source.loaded = {
'0': {
status: 'done',
parse
}
};

const callback1 = t.spy();
const callback2 = t.spy();
const callback3 = t.spy();
source.reloadTile({ uid: 0 }, callback1);
t.equal(parse.callCount, 1);

source.loaded[0].status = 'parsing';
source.reloadTile({ uid: 0 }, callback2);
t.equal(parse.callCount, 1);

parse.firstCall.args[3]();
t.equal(parse.callCount, 2);
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 0);
t.equal(callback3.callCount, 0);

source.reloadTile({ uid: 0 }, callback3);
t.equal(parse.callCount, 2);
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 0);
t.equal(callback3.callCount, 0);

parse.secondCall.args[3]();
t.equal(parse.callCount, 3);
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 1);
t.equal(callback3.callCount, 0);

parse.thirdCall.args[3]();
t.equal(callback1.callCount, 1);
t.equal(callback2.callCount, 1);
t.equal(callback3.callCount, 1);

t.end();
});

test('VectorTileWorkerSource provides resource timing information', (t) => {
const rawTileData = fs.readFileSync(path.join(__dirname, '/../../fixtures/mbsv5-6-18-23.vector.pbf'));

Expand Down

0 comments on commit b42a665

Please sign in to comment.