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 14 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
19 changes: 5 additions & 14 deletions conf/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ play {
maxDiskBuffer = 1G
}
filters = "com.scalableminds.webknossos.datastore.Filters"
fileMimeTypes = ${play.http.fileMimeTypes} """
wasm=application/wasm
"""
}
filters.headers {
# Unset some of the security filters enabled in datastore.Filters
Expand Down Expand Up @@ -175,20 +178,8 @@ mail {
}
}

# SQL database connection
slick = {
profile = "slick.jdbc.PostgresProfile$"
codegen.package = "com.scalableminds.webknossos.schema"
db = {
url = "jdbc:postgresql://localhost/webknossos"
url = ${?POSTGRES_URL}
driver = org.postgresql.Driver
keepAliveConnection = true
user = "postgres"
password = "postgres"
queueSize = 5000
}
}
# SQL Slick Database Connection Config in Subfile to provide it also to the AssetGeneration task
include "slick.conf"

# Authentication via cookies and tokens
silhouette {
Expand Down
14 changes: 14 additions & 0 deletions conf/slick.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SQL database connection
slick = {
profile = "slick.jdbc.PostgresProfile$"
codegen.package = "com.scalableminds.webknossos.schema"
db = {
url = "jdbc:postgresql://localhost/webknossos"
url = ${?POSTGRES_URL}
driver = org.postgresql.Driver
keepAliveConnection = true
user = "postgres"
password = "postgres"
queueSize = 5000
}
}
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
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
Copy link
Member

Choose a reason for hiding this comment

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

Instead of importing the mock in every test file, I think it should work and would be more foolproof to import it once in frontend/javascripts/test/enzyme/e2e-setup.ts or do you think the import order could be problematic, then? 🤔

Sorry to comment on the mocking again. It's no big deal if you leave it as-is.

import type { APIAnnotation } from "types/api_flow_types";
import { APIAnnotationTypeEnum } from "types/api_flow_types";
import { createTreeMapFromTreeArray } from "oxalis/model/reducers/skeletontracing_reducer_helpers";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import type { APIDataset } from "types/api_flow_types";
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import {
tokenUserA,
setCurrToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import type { APIProject, APIProjectUpdater } from "types/api_flow_types";
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import {
tokenUserA,
setCurrToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import { resetDatabase, replaceVolatileValues, writeTypeCheckingFile } from "test/enzyme/e2e-setup";
import * as api from "admin/admin_rest_api";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import {
tokenUserA,
setCurrToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import {
tokenUserA,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import {
tokenUserA,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import _ from "lodash";
import moment from "moment";
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "test/mocks/lz4";
import {
tokenUserA,
setCurrToken,
Expand Down
1 change: 1 addition & 0 deletions frontend/javascripts/test/controller/url_manager.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 UrlManager, { updateTypeAndId, encodeUrlHash } from "oxalis/controller/url_manager";
import { location } from "libs/window";
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
4 changes: 4 additions & 0 deletions frontend/javascripts/test/mocks/lz4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import mockRequire from "mock-require";
import * as lz4 from "lz4-wasm-nodejs";

mockRequire("lz4-wasm", lz4);
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
2 changes: 1 addition & 1 deletion frontend/javascripts/test/model/model.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-nocheck
import _ from "lodash";
import "test/mocks/lz4";
import mockRequire from "mock-require";
import sinon from "sinon";
import test from "ava";
Expand All @@ -9,7 +10,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,4 +1,5 @@
import mock from "mock-require";
import "test/mocks/lz4";
import test, { ExecutionContext } from "ava";
import { Vector4 } from "oxalis/constants";

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
Loading