Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use LZ4 with WASM for volume saving/undo/redo #6652

Merged
merged 21 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d029734
fix conversion of NaN to big int
philippotto Nov 21, 2022
b0e4ed8
use lz4-wasm for compression/decompression of buckets (for undo/redo)
philippotto Nov 21, 2022
ec39a18
also use lz4-wasm for compression of buckets (for saving)
philippotto Nov 21, 2022
d8c79b0
clean up lz-wasm usage
philippotto Nov 21, 2022
c4bb49b
fix tests by using different lz4 library there via mocking
philippotto Nov 21, 2022
1724ea2
more mocks
philippotto Nov 21, 2022
7e60e85
update changelog
philippotto Nov 21, 2022
ddf9f5c
more mocks
philippotto Nov 21, 2022
6384566
add missing file
philippotto Nov 21, 2022
b6d7f24
fix accidental mock of non-spec files
philippotto Nov 22, 2022
194c0b8
fix accidental mock of non-spec files
philippotto Nov 22, 2022
2b9cc24
also mock in e2e tests
philippotto Nov 22, 2022
f96cb64
add wasm mime type
fm3 Nov 22, 2022
3a0abd8
extract slick conf
fm3 Nov 22, 2022
df53044
Merge branch 'master' of github.com:scalableminds/webknossos into lz4…
philippotto Nov 23, 2022
062f846
extract lz4 mock in e2e specs away using e2e-setup
philippotto Nov 23, 2022
c86c647
re-add slow lz4js library to conduct performance comparison on dev in…
philippotto Nov 23, 2022
738d29f
Revert "re-add slow lz4js library to conduct performance comparison o…
philippotto Nov 23, 2022
7f19d04
tune down changelog entry
philippotto Nov 23, 2022
dad8f0d
bump pako version (used for gzip compression when sending buckets to …
philippotto Nov 23, 2022
f581e79
Merge branch 'master' into lz4-wasm
philippotto Nov 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
- Re-phrased some backend (error) messages to improve clarity and provide helping hints. [#6616](https://github.com/scalableminds/webknossos/pull/6616)
- The layer visibility is now encoded in the sharing link. The user opening the link will see the same layers that were visible when copying the link. [#6634](https://github.com/scalableminds/webknossos/pull/6634)
- Voxelytics workflows can now be viewed by anyone with the link who is in the right organization. [#6622](https://github.com/scalableminds/webknossos/pull/6622)

- Major performance improvements to volume saving/undo/redo. [#6652](https://github.com/scalableminds/webknossos/pull/6652)

### Fixed
- Fixed a bug in the dataset import view, where the layer name text field would lose focus after each key press. [#6615](https://github.com/scalableminds/webknossos/pull/6615)
- Fixed importing NGFF Zarr datasets with non-scale transforms. [#6621](https://github.com/scalableminds/webknossos/pull/6621)
Expand Down
2 changes: 1 addition & 1 deletion frontend/javascripts/libs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ export function castForArrayType(uncastNumber: number, data: TypedArray): number
}

export function convertNumberTo64Bit(num: number | null): [Vector4, Vector4] {
if (num == null) {
if (num == null || isNaN(num)) {
daniel-wer marked this conversation as resolved.
Show resolved Hide resolved
return [
[0, 0, 0, 0],
[0, 0, 0, 0],
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/api/api_v2.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import { InputKeyboardNoLoop } from "libs/input";
import Model from "oxalis/model";
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/controller/url_manager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import { V3 } from "libs/mjs";
import { applyState } from "oxalis/model_initialization";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import * as THREE from "three";
import _ from "lodash";
import { DataBucket, bucketDebuggingFlags } from "oxalis/model/bucket_data_handling/bucket";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import _ from "lodash";
import "test/mocks/lz4";
import type { Vector3, LabeledVoxelsMap, Vector4 } from "oxalis/constants";
import constants from "oxalis/constants";
import { map3 } from "libs/utils";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'lz4j... Remove this comment to see the full error message
import lz4 from "lz4js";
import { expose } from "./comlink_wrapper";
import * as lz4 from "lz4-wasm";

function compressLz4Block(data: Uint8Array, compress: boolean): Uint8Array {
if (compress) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import Base64 from "base64-js";
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'lz4j... Remove this comment to see the full error message
import lz4 from "lz4js";
import * as lz4wasm from "lz4-wasm";
import { expose } from "./comlink_wrapper";

function compressLz4Block(data: Uint8Array): Uint8Array {
// Backend expects the frame-less version of lz4,
// so we need to call lz4.compressBlock rather than compress
const hashSize = 1 << 16;
const hashTable = new Uint32Array(hashSize);
const compressedBuffer = new Uint8Array(data.length);
const compressedSize = lz4.compressBlock(data, compressedBuffer, 0, data.length, hashTable);
return compressedBuffer.slice(0, compressedSize);
// The backend expects the block (frame-less) version of lz4.
// lz4-wasm uses the block version, but prepends the size of the
// compressed data. Therefore, we strip the first 4 bytes.
const newCompressed = lz4wasm.compress(data);
return newCompressed.slice(4);
}

export function byteArrayToLz4Base64(byteArray: Uint8Array): string {
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/api/api_skeleton_latest.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import { __setupOxalis, KeyboardJS } from "test/helpers/apiHelpers";
import { makeBasicGroupObject } from "oxalis/view/right-border-tabs/tree_hierarchy_view_helpers";
import { setMappingEnabledAction } from "oxalis/model/actions/settings_actions";
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/api/api_v2.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import { __setupOxalis, KeyboardJS } from "test/helpers/apiHelpers";
import { setMappingEnabledAction } from "oxalis/model/actions/settings_actions";
import Store from "oxalis/store";
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/api/api_volume_latest.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import { AnnotationToolEnum } from "oxalis/constants";
import { __setupOxalis } from "test/helpers/apiHelpers";
import test from "ava";
Expand Down
3 changes: 2 additions & 1 deletion frontend/javascripts/test/geometries/skeleton.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Integration tests for skeleton.js
import "test/mocks/lz4";
import _ from "lodash";
import { getSkeletonTracing } from "oxalis/model/accessors/skeletontracing_accessor";
import * as Utils from "libs/utils";
Expand All @@ -7,7 +8,7 @@ import test from "ava";
import { Vector3 } from "oxalis/constants";
import { OxalisState } from "oxalis/store";
import { tracing, annotation } from "../fixtures/skeletontracing_server_objects";
mockRequire.stopAll();

mockRequire("app", {
currentUser: {
firstName: "SCM",
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/libs/nml.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import _ from "lodash";
import update from "immutability-helper";
import sinon from "sinon";
Expand Down
3 changes: 2 additions & 1 deletion frontend/javascripts/test/model/binary/cube.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import _ from "lodash";
import { ResolutionInfo } from "oxalis/model/accessors/dataset_accessor";
import { tracing as skeletontracingServerObject } from "test/fixtures/skeletontracing_server_objects";
Expand All @@ -9,7 +10,7 @@ import datasetServerObject from "test/fixtures/dataset_server_object";
import mockRequire from "mock-require";
import runAsync from "test/helpers/run-async";
import sinon from "sinon";
mockRequire.stopAll();

const StoreMock = {
getState: () => ({
dataset: datasetServerObject,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import "test/mocks/lz4";
import mockRequire from "mock-require";

const REQUEST_ID = "dummyRequestId";
const UidMock = {
getUid: () => REQUEST_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import runAsync from "test/helpers/run-async";
import sinon from "sinon";
import type { TestInterface } from "ava";
import anyTest from "ava";
import "test/mocks/lz4";

mockRequire("oxalis/model/sagas/root_saga", function* () {
yield;
});
Expand Down
1 change: 0 additions & 1 deletion frontend/javascripts/test/model/model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
annotation as ANNOTATION,
} from "../fixtures/skeletontracing_server_objects";
import DATASET from "../fixtures/dataset_server_object";
mockRequire.stopAll();

function makeModelMock() {
class ModelMock {}
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/model/model_resolutions.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import test from "ava";
import mockRequire from "mock-require";
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import { ResolutionInfo } from "oxalis/model/accessors/dataset_accessor";
import { tracing as skeletontracingServerObject } from "test/fixtures/skeletontracing_server_objects";
import { tracing as volumetracingServerObject } from "test/fixtures/volumetracing_server_objects";
Expand All @@ -8,7 +9,7 @@ import anyTest from "ava";
import datasetServerObject from "test/fixtures/dataset_server_object";
import mockRequire from "mock-require";
import sinon from "sinon";
mockRequire.stopAll();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the stopAlls reverted the lz4 mocking (which is necessary since the lz4-wasm module is different for browser and node, unfortunately). it took me a while to figure out that stopAll was the culprit, since it's so inconspicuously in the code. luckily, these statements weren't even necessary.

it's a bit unfortunate that the lz4 mock needs to be at that many places, but I couldn't figure out a better way..


const StoreMock = {
getState: () => ({
dataset: datasetServerObject,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-nocheck
/* eslint-disable no-useless-computed-key */
import "test/mocks/lz4";
import _ from "lodash";
import update from "immutability-helper";
import { rgbs as colors } from "libs/color_generator";
Expand All @@ -8,7 +9,7 @@ import DiffableMap from "libs/diffable_map";
import EdgeCollection from "oxalis/model/edge_collection";
import mock from "mock-require";
import test from "ava";
mock.stopAll();

mock("app", {
currentUser: {
firstName: "SCM",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @ts-nocheck
import "test/mocks/lz4";
import update from "immutability-helper";
import { getFirstVolumeTracingOrFail } from "test/helpers/apiHelpers";
import { AnnotationToolEnum } from "oxalis/constants";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import test from "ava";
import { AnnotationToolEnum, AnnotationTool } from "oxalis/constants";
import mockRequire from "mock-require";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-nocheck
import _ from "lodash";
import "test/mocks/lz4";
import type { Flycam, OxalisState, Tree, TreeMap } from "oxalis/store";
import { diffSkeletonTracing } from "oxalis/model/sagas/skeletontracing_saga";
import { enforceSkeletonTracing } from "oxalis/model/accessors/skeletontracing_accessor";
Expand Down
4 changes: 3 additions & 1 deletion frontend/javascripts/test/sagas/prefetch_saga.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import "test/mocks/lz4";
import Model from "oxalis/model";
import constants from "oxalis/constants";
import mockRequire from "mock-require";
import test from "ava";
import { expectValueDeepEqual, execCall } from "../helpers/sagaHelpers";
import DATASET from "../fixtures/dataset_server_object";
mockRequire.stopAll();

mockRequire("oxalis/model/sagas/root_saga", function* () {
yield;
});

const { call } = mockRequire.reRequire("redux-saga/effects");
const { triggerDataPrefetching, prefetchForArbitraryMode, prefetchForPlaneMode } =
mockRequire.reRequire("oxalis/model/sagas/prefetch_saga");
Expand Down
2 changes: 2 additions & 0 deletions frontend/javascripts/test/sagas/saga_integration.mock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import mockRequire from "mock-require";
import * as antd from "antd";
import _ from "lodash";
import "test/mocks/lz4";

const REQUEST_ID = "dummyRequestId";
const UidMock = {
getUid: () => REQUEST_ID,
Expand Down
3 changes: 2 additions & 1 deletion frontend/javascripts/test/sagas/save_saga.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import { alert } from "libs/window";
import { setSaveBusyAction } from "oxalis/model/actions/save_actions";
import DiffableMap from "libs/diffable_map";
Expand All @@ -7,7 +8,7 @@ import mockRequire from "mock-require";
import test from "ava";
import { createSaveQueueFromUpdateActions } from "../helpers/saveHelpers";
import { expectValueDeepEqual } from "../helpers/sagaHelpers";
mockRequire.stopAll();

const TIMESTAMP = 1494695001688;
const DateMock = {
now: () => TIMESTAMP,
Expand Down
2 changes: 2 additions & 0 deletions frontend/javascripts/test/sagas/skeletontracing_saga.mock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import "test/mocks/lz4";
import mockRequire from "mock-require";

const REQUEST_ID = "dummyRequestId";
const UidMock = {
getUid: () => REQUEST_ID,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import test from "ava";
import mockRequire from "mock-require";
import { waitForCondition } from "libs/utils";
import "test/mocks/lz4";
import "test/sagas/saga_integration.mock";
import { __setupOxalis, createBucketResponseFunction } from "test/helpers/apiHelpers";
import { restartSagaAction, wkReadyAction } from "oxalis/model/actions/actions";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import test from "ava";
import mockRequire from "mock-require";
import { waitForCondition } from "libs/utils";
import "test/mocks/lz4";
import "test/sagas/saga_integration.mock";
import { __setupOxalis, createBucketResponseFunction } from "test/helpers/apiHelpers";
import { restartSagaAction, wkReadyAction } from "oxalis/model/actions/actions";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import mockRequire from "mock-require";
import "test/mocks/lz4";

const REQUEST_ID = "dummyRequestId";
const UidMock = {
getUid: () => REQUEST_ID,
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/shaders/shader_syntax.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import { getLookupBufferSize } from "oxalis/model/bucket_data_handling/data_rendering_logic";
import constants from "oxalis/constants";
import getMainFragmentShader from "oxalis/shaders/main_data_fragment.glsl";
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"less": "^4.0.0",
"less-loader": "^10.2.0",
"lint-staged": "^7.3.0",
"lz4-wasm-nodejs": "^0.9.2",
"merge-img": "^2.1.2",
"mock-require": "^1.2.1",
"node-fetch": "^2.6.7",
Expand Down Expand Up @@ -183,7 +184,7 @@
"jsonschema": "^1.2.4",
"jszip": "^3.7.0",
"lodash": "^4.17.21",
"lz4js": "^0.2.0",
"lz4-wasm": "^0.9.2",
"memoize-one": "^6.0.0",
"mini-css-extract-plugin": "^2.5.2",
"minisearch": "^5.0.0",
Expand Down
8 changes: 8 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module.exports = function (env = {}) {
};

return {
experiments: { asyncWebAssembly: true },
entry: {
main: "main.tsx",
light: "style_light.ts",
Expand Down Expand Up @@ -136,6 +137,13 @@ module.exports = function (env = {}) {
fallback: {
// Needed for jsonschema
url: require.resolve("url/"),
// Needed for lz4-wasm-nodejs (which is only used in test context, which is
// why we use empty modules)
path: false,
util: false,
fs: false,
// Needed for mock-require
module: false,
},
},
optimization: {
Expand Down
13 changes: 9 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8722,10 +8722,15 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"

lz4js@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/lz4js/-/lz4js-0.2.0.tgz#09f1a397cb2158f675146c3351dde85058cb322f"
integrity sha1-CfGjl8shWPZ1FGwzUd3oUFjLMi8=
lz4-wasm-nodejs@^0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/lz4-wasm-nodejs/-/lz4-wasm-nodejs-0.9.2.tgz#eaa3184ac048e1af9bd0ec82f89de8e8f158c6c7"
integrity sha512-hSwgJPS98q/Oe/89Y1OxzeA/UdnASG8GvldRyKa7aZyoAFCC8VPRtViBSava7wWC66WocjUwBpWau2rEmyFPsw==

lz4-wasm@^0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/lz4-wasm/-/lz4-wasm-0.9.2.tgz#2047b8a9771ad33b1699c350cda3e86249fbbb46"
integrity sha512-8Y/OvG/nTQNWR242NhLmjI7VzLMRKFaxg/+Pxi/vkczgFdrS4qiJ8l6n30XyNJyc0TB5C66Ncdjq345Kx5XsvQ==

magic-string@^0.25.7:
version "0.25.7"
Expand Down