SQL Kernel Improvements/Removing Spark Code from Core/Attach to Changes (#3790)

* Scenarios work besides loading saved kernel

* Fix compilation issue

* Save and load functional

* Fix loading kernesl issue when sql kernel is not enabled

* Fix language mapping to not be hardcoded any longer

* Remove unnecessary comment

* PR Comments vol. 1

* Code cleanup, use ConnectionProfile instead of IConnectionProfile when accessing serverName

* PR changes vol. 2

* One final comment for PR

* Fix linting issue
This commit is contained in:
Chris LaFreniere
2019-01-25 18:54:04 -08:00
committed by GitHub
parent ea67859de7
commit 43be88a37c
29 changed files with 768 additions and 627 deletions

View File

@@ -17,13 +17,13 @@ import { NotebookChangeType, CellType } from 'sql/parts/notebook/models/contract
import { nbversion } from '../notebookConstants';
import * as notebookUtils from '../notebookUtils';
import { INotebookManager, SQL_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/common/notebookService';
import { SparkMagicContexts } from 'sql/parts/notebook/models/sparkMagicContexts';
import { NotebookContexts } from 'sql/parts/notebook/models/notebookContexts';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { NotebookConnection } from 'sql/parts/notebook/models/notebookConnection';
import { INotification, Severity } from 'vs/platform/notification/common/notification';
import { Schemas } from 'vs/base/common/network';
import URI from 'vs/base/common/uri';
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
/*
* Used to control whether a message in a dialog/wizard is displayed as an error,
@@ -58,11 +58,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
private _savedKernelInfo: nb.IKernelInfo;
private readonly _nbformat: number = nbversion.MAJOR_VERSION;
private readonly _nbformatMinor: number = nbversion.MINOR_VERSION;
private _hadoopConnection: NotebookConnection;
private _defaultKernel: nb.IKernelSpec;
private _activeConnection: ConnectionProfile;
private _activeCell: ICellModel;
private _providerId: string;
private _isNewNotebook: boolean = true;
private _defaultKernel: nb.IKernelSpec;
private _kernelDisplayNameToConnectionProviderIds: Map<string, string[]> = new Map<string, string[]>();
private _kernelDisplayNameToNotebookProviderIds: Map<string, string> = new Map<string, string>();
constructor(private notebookOptions: INotebookModelOptions, startSessionImmediately?: boolean, private connectionProfile?: IConnectionProfile) {
super();
@@ -74,6 +75,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
}
this._trustedMode = false;
this._providerId = notebookOptions.providerId;
this.notebookOptions.standardKernels.forEach(kernel => {
this._kernelDisplayNameToConnectionProviderIds.set(kernel.name, kernel.connectionProviderIds);
this._kernelDisplayNameToNotebookProviderIds.set(kernel.name, kernel.notebookProvider);
});
this._defaultKernel = notebookOptions.defaultKernel;
}
public get notebookManagers(): INotebookManager[] {
@@ -171,10 +177,6 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._trustedMode;
}
public get isNewNotebook(): boolean {
return this._isNewNotebook;
}
public get providerId(): string {
return this._providerId;
}
@@ -188,8 +190,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
}
}
public get hadoopConnection(): NotebookConnection {
return this._hadoopConnection;
public get activeConnection(): IConnectionProfile {
return this._activeConnection;
}
/**
@@ -207,6 +209,14 @@ export class NotebookModel extends Disposable implements INotebookModel {
return this._onClientSessionReady.event;
}
public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] {
let ids = [];
if (kernelDisplayName) {
ids = this._kernelDisplayNameToConnectionProviderIds.get(kernelDisplayName);
}
return !ids ? [] : ids;
}
public async requestModelLoad(isTrusted: boolean = false): Promise<void> {
try {
this._trustedMode = isTrusted;
@@ -223,9 +233,12 @@ export class NotebookModel extends Disposable implements INotebookModel {
version: ''
};
if (contents) {
this._isNewNotebook = false;
this._defaultLanguageInfo = this.getDefaultLanguageInfo(contents);
this._savedKernelInfo = this.getSavedKernelInfo(contents);
this.setProviderIdForKernel(this._savedKernelInfo);
if (this._savedKernelInfo) {
this._defaultKernel = this._savedKernelInfo;
}
if (contents.cells && contents.cells.length > 0) {
this._cells = contents.cells.map(c => factory.createCell(c, { notebook: this, isTrusted: isTrusted }));
}
@@ -338,15 +351,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
if (!this._activeClientSession) {
this._activeClientSession = clientSession;
}
let profile = this.connectionProfile as IConnectionProfile;
let profile = new ConnectionProfile(this.notebookOptions.capabilitiesService, this.connectionProfile);
if (this.isValidKnoxConnection(profile)) {
this._hadoopConnection = new NotebookConnection(this.connectionProfile);
if (this.isValidConnection(profile)) {
this._activeConnection = profile;
} else {
this._hadoopConnection = undefined;
this._activeConnection = undefined;
}
clientSession.initialize(this._hadoopConnection);
clientSession.initialize(this._activeConnection);
this._sessionLoadFinished = clientSession.ready.then(async () => {
if (clientSession.isInErrorState) {
this.setErrorState(clientSession.errorMessage);
@@ -360,8 +373,10 @@ export class NotebookModel extends Disposable implements INotebookModel {
});
}
private isValidKnoxConnection(profile: IConnectionProfile | connection.Connection) {
return profile && profile.providerName === notebookConstants.hadoopKnoxProviderName && profile.options[notebookConstants.hostPropName] !== undefined;
private isValidConnection(profile: IConnectionProfile | connection.Connection) {
let standardKernels = this.notebookOptions.standardKernels.find(kernel => this._savedKernelInfo && kernel.name === this._savedKernelInfo.display_name);
let connectionProviderIds = standardKernels ? standardKernels.connectionProviderIds : undefined;
return profile && connectionProviderIds && connectionProviderIds.find(provider => provider === profile.providerName) !== undefined;
}
public get languageInfo(): nb.ILanguageInfo {
@@ -380,45 +395,49 @@ export class NotebookModel extends Disposable implements INotebookModel {
}
public doChangeKernel(kernelSpec: nb.IKernelSpec): Promise<void> {
this.findProviderIdForKernel(kernelSpec);
return this._activeClientSession.changeKernel(kernelSpec)
.then((kernel) => {
kernel.ready.then(() => {
if (kernel.info) {
this.updateLanguageInfo(kernel.info.language_info);
}
}, err => undefined);
return this.updateKernelInfo(kernel);
}).catch((err) => {
this.notifyError(localize('changeKernelFailed', 'Failed to change kernel: {0}', notebookUtils.getErrorMessage(err)));
// TODO should revert kernels dropdown
});
this.setProviderIdForKernel(kernelSpec);
if (this._activeClientSession && this._activeClientSession.isReady) {
return this._activeClientSession.changeKernel(kernelSpec)
.then((kernel) => {
this.updateKernelInfo(kernel);
kernel.ready.then(() => {
if (kernel.info) {
this.updateLanguageInfo(kernel.info.language_info);
}
}, err => undefined);
}).catch((err) => {
this.notifyError(localize('changeKernelFailed', 'Failed to change kernel: {0}', notebookUtils.getErrorMessage(err)));
// TODO should revert kernels dropdown
});
}
this.notifyError(localize('noActiveClientSessionFound', 'No active client session was found.'));
return Promise.resolve();
}
public changeContext(host: string, newConnection?: IConnectionProfile): void {
public changeContext(server: string, newConnection?: IConnectionProfile): void {
try {
if (!newConnection) {
newConnection = this._activeContexts.otherConnections.find((connection) => connection.options['host'] === host);
newConnection = this._activeContexts.otherConnections.find((connection) => connection.serverName === server);
}
if (!newConnection && this._activeContexts.defaultConnection.options['host'] === host) {
if (!newConnection && (this._activeContexts.defaultConnection.serverName === server)) {
newConnection = this._activeContexts.defaultConnection;
}
SparkMagicContexts.configureContext();
this._hadoopConnection = new NotebookConnection(newConnection);
this.refreshConnections(newConnection);
this._activeClientSession.updateConnection(this._hadoopConnection);
let newConnectionProfile = new ConnectionProfile(this.notebookOptions.capabilitiesService, newConnection);
this._activeConnection = newConnectionProfile;
this.refreshConnections(newConnectionProfile);
this._activeClientSession.updateConnection(this._activeConnection);
} catch (err) {
let msg = notebookUtils.getErrorMessage(err);
this.notifyError(localize('changeContextFailed', 'Changing context failed: {0}', msg));
}
}
private refreshConnections(newConnection: IConnectionProfile) {
if (this.isValidKnoxConnection(newConnection) &&
this._hadoopConnection.connectionProfile.id !== '-1' &&
this._hadoopConnection.connectionProfile.id !== this._activeContexts.defaultConnection.id) {
private refreshConnections(newConnection: ConnectionProfile) {
if (this.isValidConnection(newConnection) &&
this._activeConnection.id !== '-1' &&
this._activeConnection.id !== this._activeContexts.defaultConnection.id) {
// Put the defaultConnection to the head of otherConnections
if (this.isValidKnoxConnection(this._activeContexts.defaultConnection)) {
if (this.isValidConnection(this._activeContexts.defaultConnection)) {
this._activeContexts.otherConnections = this._activeContexts.otherConnections.filter(conn => conn.id !== this._activeContexts.defaultConnection.id);
this._activeContexts.otherConnections.unshift(this._activeContexts.defaultConnection);
}
@@ -439,18 +458,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
try {
let sessionManager = this.notebookManager.sessionManager;
if (sessionManager) {
let defaultKernel = SparkMagicContexts.getDefaultKernel(sessionManager.specs, this.connectionProfile, this._savedKernelInfo, this.notebookOptions.notificationService);
this._defaultKernel = defaultKernel;
if (!this._defaultKernel) {
this._defaultKernel = NotebookContexts.getDefaultKernel(sessionManager.specs, this.connectionProfile, this._savedKernelInfo);
}
this._clientSessions.forEach(clientSession => {
clientSession.statusChanged(async (session) => {
if (session && session.defaultKernelLoaded === true) {
this._kernelsChangedEmitter.fire(defaultKernel);
} else if (session && !session.defaultKernelLoaded) {
this._kernelsChangedEmitter.fire({ name: notebookConstants.python3, display_name: notebookConstants.python3DisplayName });
}
this._kernelsChangedEmitter.fire(session.kernel);
});
});
this.doChangeKernel(defaultKernel);
this.doChangeKernel(this._defaultKernel);
}
} catch (err) {
let msg = notebookUtils.getErrorMessage(err);
@@ -484,6 +500,15 @@ export class NotebookModel extends Disposable implements INotebookModel {
return kernel;
}
private getDisplayNameFromSpecName(kernelid: string): string {
let newKernel = this.notebookManager.sessionManager.specs.kernels.find(kernel => kernel.name === kernelid);
let newKernelDisplayName;
if (newKernel) {
newKernelDisplayName = newKernel.display_name;
}
return newKernelDisplayName;
}
private setErrorState(errMsg: string): void {
this._inErrorState = true;
let msg = localize('startSessionFailed', 'Could not start session: {0}', errMsg);
@@ -499,6 +524,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
public async handleClosed(): Promise<void> {
try {
if (this._activeClientSession) {
try {
await this._activeClientSession.ready;
} catch(err) {
this.notifyError(localize('shutdownClientSessionError', 'A client session error occurred when closing the notebook: {0}', err));
}
await this._activeClientSession.shutdown();
this._clientSessions = undefined;
this._activeClientSession = undefined;
@@ -509,11 +539,13 @@ export class NotebookModel extends Disposable implements INotebookModel {
}
private async loadActiveContexts(kernelChangedArgs: nb.IKernelChangedArgs): Promise<void> {
this._activeContexts = await SparkMagicContexts.getContextsForKernel(this.notebookOptions.connectionService, kernelChangedArgs, this.connectionProfile);
this._contextsChangedEmitter.fire();
if (this.contexts.defaultConnection !== undefined && this.contexts.defaultConnection.options !== undefined) {
let defaultHadoopConnection = new NotebookConnection(this.contexts.defaultConnection);
this.changeContext(defaultHadoopConnection.host);
if (kernelChangedArgs && kernelChangedArgs.newValue && kernelChangedArgs.newValue.name) {
let kernelDisplayName = this.getDisplayNameFromSpecName(kernelChangedArgs.newValue.name);
this._activeContexts = await NotebookContexts.getContextsForKernel(this.notebookOptions.connectionService, this.getApplicableConnectionProviderIds(kernelDisplayName), kernelChangedArgs, this.connectionProfile);
this._contextsChangedEmitter.fire();
if (this.contexts.defaultConnection !== undefined && this.contexts.defaultConnection.serverName !== undefined) {
this.changeContext(this.contexts.defaultConnection.serverName);
}
}
}
@@ -555,6 +587,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
display_name: spec.display_name,
language: spec.language
};
this.clientSession.configureKernel(this._savedKernelInfo);
} catch (err) {
// Don't worry about this for now. Just use saved values
}
@@ -565,17 +598,27 @@ export class NotebookModel extends Disposable implements INotebookModel {
* Set _providerId and _activeClientSession based on a kernelSpec representing new kernel
* @param kernelSpec KernelSpec for new kernel
*/
private findProviderIdForKernel(kernelSpec: nb.IKernelSpec): void {
private setProviderIdForKernel(kernelSpec: nb.IKernelSpec): void {
let sessionManagerFound: boolean = false;
for (let i = 0; i < this.notebookManagers.length; i++) {
if (this.notebookManagers[i].sessionManager && this.notebookManagers[i].sessionManager.specs && this.notebookManagers[i].sessionManager.specs.kernels) {
let index = this.notebookManagers[i].sessionManager.specs.kernels.findIndex(kernel => kernel.name === kernelSpec.name);
if (index >= 0) {
this._activeClientSession = this._clientSessions[i];
this._providerId = this.notebookManagers[i].providerId;
sessionManagerFound = true;
break;
}
}
}
// If no SessionManager exists, utilize passed in StandardKernels to see if we can intelligently set _providerId
if (!sessionManagerFound) {
let provider = this._kernelDisplayNameToNotebookProviderIds.get(kernelSpec.display_name);
if (provider) {
this._providerId = provider;
}
}
}
/**
* Serialize the model to JSON.