Improve migration perf (#99773)

* Do not clone state, use TypeCheck it's not mutated

* do not recreate context for every migration

* use more optional semver check

* update SavedObjectMigrationContext type

* add a test model returns new state object

* update docs

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Mikhail Shustov 2021-05-17 11:46:57 +02:00 committed by GitHub
parent 5e410f5d86
commit d8a2f8f95c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 21 deletions

View file

@ -9,5 +9,5 @@ The version in which this object type is being converted to a multi-namespace ty
<b>Signature:</b>
```typescript
convertToMultiNamespaceTypeVersion?: string;
readonly convertToMultiNamespaceTypeVersion?: string;
```

View file

@ -9,5 +9,5 @@ logger instance to be used by the migration handler
<b>Signature:</b>
```typescript
log: SavedObjectsMigrationLogger;
readonly log: SavedObjectsMigrationLogger;
```

View file

@ -9,5 +9,5 @@ The migration version that this migration function is defined for
<b>Signature:</b>
```typescript
migrationVersion: string;
readonly migrationVersion: string;
```

View file

@ -661,13 +661,14 @@ function wrapWithTry(
migrationFn: SavedObjectMigrationFn,
log: Logger
) {
const context = Object.freeze({
log: new MigrationLogger(log),
migrationVersion: version,
convertToMultiNamespaceTypeVersion: type.convertToMultiNamespaceTypeVersion,
});
return function tryTransformDoc(doc: SavedObjectUnsanitizedDoc) {
try {
const context = {
log: new MigrationLogger(log),
migrationVersion: version,
convertToMultiNamespaceTypeVersion: type.convertToMultiNamespaceTypeVersion,
};
const result = migrationFn(doc, context);
// A basic sanity check to help migration authors detect basic errors

View file

@ -56,15 +56,15 @@ export interface SavedObjectMigrationContext {
/**
* logger instance to be used by the migration handler
*/
log: SavedObjectsMigrationLogger;
readonly log: SavedObjectsMigrationLogger;
/**
* The migration version that this migration function is defined for
*/
migrationVersion: string;
readonly migrationVersion: string;
/**
* The version in which this object type is being converted to a multi-namespace type
*/
convertToMultiNamespaceTypeVersion?: string;
readonly convertToMultiNamespaceTypeVersion?: string;
}
/**

View file

@ -198,6 +198,31 @@ describe('migrations v2 model', () => {
});
describe('model transitions from', () => {
it('transition returns new state', () => {
const initState: State = {
...baseState,
controlState: 'INIT',
currentAlias: '.kibana',
versionAlias: '.kibana_7.11.0',
versionIndex: '.kibana_7.11.0_001',
};
const res: ResponseType<'INIT'> = Either.right({
'.kibana_7.11.0_001': {
aliases: {
'.kibana': {},
'.kibana_7.11.0': {},
},
mappings: {
properties: {},
},
settings: {},
},
});
const newState = model(initState, res);
expect(newState).not.toBe(initState);
});
describe('INIT', () => {
const initState: State = {
...baseState,

View file

@ -9,7 +9,7 @@
import { gt, valid } from 'semver';
import * as Either from 'fp-ts/lib/Either';
import * as Option from 'fp-ts/lib/Option';
import { cloneDeep } from 'lodash';
import { AliasAction, FetchIndexResponse, isLeftTypeof, RetryableEsClientError } from './actions';
import { AllActionStates, InitState, State } from './types';
import { IndexMapping } from '../mappings';
@ -187,7 +187,7 @@ export const model = (currentState: State, resW: ResponseType<AllActionStates>):
// control state using:
// `const res = resW as ResponseType<typeof stateP.controlState>;`
let stateP: State = cloneDeep(currentState);
let stateP: State = currentState;
// Handle retryable_es_client_errors. Other left values need to be handled
// by the control state specific code below.

View file

@ -381,7 +381,7 @@ export interface LegacyDeleteState extends LegacyBaseState {
readonly controlState: 'LEGACY_DELETE';
}
export type State =
export type State = Readonly<
| FatalState
| InitState
| DoneState
@ -411,7 +411,8 @@ export type State =
| LegacySetWriteBlockState
| LegacyReindexState
| LegacyReindexWaitForTaskState
| LegacyDeleteState;
| LegacyDeleteState
>;
export type AllControlStates = State['controlState'];
/**

View file

@ -2152,9 +2152,9 @@ export interface SavedObjectExportBaseOptions {
// @public
export interface SavedObjectMigrationContext {
convertToMultiNamespaceTypeVersion?: string;
log: SavedObjectsMigrationLogger;
migrationVersion: string;
readonly convertToMultiNamespaceTypeVersion?: string;
readonly log: SavedObjectsMigrationLogger;
readonly migrationVersion: string;
}
// @public

View file

@ -5,8 +5,7 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import semverSatisfies from 'semver/functions/satisfies';
import Semver from 'semver';
import { SavedObjectAttributes, SavedObjectReference } from '../../../core/types';
import { DashboardContainerStateWithType, DashboardPanelState } from './types';
import { EmbeddablePersistableStateService } from '../../embeddable/common/types';
@ -24,7 +23,7 @@ export interface SavedObjectAttributesAndReferences {
}
const isPre730Panel = (panel: Record<string, string>): boolean => {
return 'version' in panel ? semverSatisfies(panel.version, '<7.3') : true;
return 'version' in panel ? Semver.gt('7.3.0', panel.version) : true;
};
function dashboardAttributesToState(