-
Notifications
You must be signed in to change notification settings - Fork 323
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
Pre compute suggestion db during build time #5698
Changes from 34 commits
b95a302
6bb4d43
9c84027
b84603e
1ee00d3
e2ac361
d62ec42
560a107
b68da75
8f7314e
2fbdf75
f413b62
958cc78
1ff4c25
ce821b1
5bff1ab
f480e03
335305a
b4a98a4
6638c9d
283b6f5
9081707
0e769c1
6a96e38
77c5a2b
009b595
31773a6
a45898a
5314e10
1447ed0
20c2e40
89739c0
36862c6
3468399
952f0f6
4742f5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import java.util.concurrent.Executors | |
import akka.actor.{Actor, ActorRef, Props, Stash, Status} | ||
import akka.pattern.pipe | ||
import com.typesafe.scalalogging.LazyLogging | ||
import org.enso.docs.sections.DocSectionsBuilder | ||
import org.enso.languageserver.capability.CapabilityProtocol.{ | ||
AcquireCapability, | ||
CapabilityAcquired, | ||
|
@@ -111,6 +112,12 @@ final class SuggestionsHandler( | |
.subscribe(self, classOf[Api.ExpressionUpdates]) | ||
context.system.eventStream | ||
.subscribe(self, classOf[Api.SuggestionsDatabaseModuleUpdateNotification]) | ||
context.system.eventStream.subscribe( | ||
self, | ||
classOf[Api.SuggestionsDatabaseSuggestionsLoadedNotification] | ||
) | ||
context.system.eventStream | ||
.subscribe(self, classOf[Api.LibraryLoaded]) | ||
context.system.eventStream.subscribe(self, classOf[ProjectNameChangedEvent]) | ||
context.system.eventStream.subscribe(self, classOf[FileDeletedEvent]) | ||
context.system.eventStream | ||
|
@@ -122,7 +129,7 @@ final class SuggestionsHandler( | |
override def receive: Receive = | ||
initializing(SuggestionsHandler.Initialization()) | ||
|
||
def initializing(init: SuggestionsHandler.Initialization): Receive = { | ||
private def initializing(init: SuggestionsHandler.Initialization): Receive = { | ||
case ProjectNameChangedEvent(oldName, newName) => | ||
logger.info( | ||
"Initializing: project name changed from [{}] to [{}].", | ||
|
@@ -178,35 +185,7 @@ final class SuggestionsHandler( | |
case _ => stash() | ||
} | ||
|
||
def verifying( | ||
projectName: String, | ||
graph: TypeGraph | ||
): Receive = { | ||
case Api.Response(_, Api.VerifyModulesIndexResponse(toRemove)) => | ||
logger.info("Verifying: got verification response.") | ||
val removeAction = for { | ||
_ <- versionsRepo.remove(toRemove) | ||
_ <- suggestionsRepo.removeModules(toRemove) | ||
} yield SuggestionsHandler.Verified | ||
removeAction.pipeTo(self) | ||
|
||
case SuggestionsHandler.Verified => | ||
logger.info("Verified.") | ||
context.become(initialized(projectName, graph, Set(), State())) | ||
unstashAll() | ||
|
||
case Status.Failure(ex) => | ||
logger.error( | ||
"Database verification failure [{}]. {}", | ||
ex.getClass, | ||
ex.getMessage | ||
) | ||
|
||
case _ => | ||
stash() | ||
} | ||
|
||
def initialized( | ||
private def initialized( | ||
projectName: String, | ||
graph: TypeGraph, | ||
clients: Set[ClientId], | ||
|
@@ -230,12 +209,37 @@ final class SuggestionsHandler( | |
initialized(projectName, graph, clients - client.clientId, state) | ||
) | ||
|
||
case msg: Api.SuggestionsDatabaseSuggestionsLoadedNotification => | ||
logger.debug( | ||
"Starting loading suggestions for library [{}].", | ||
msg.libraryName | ||
) | ||
applyLoadedSuggestions(msg.suggestions) | ||
.onComplete { | ||
case Success(notification) => | ||
logger.debug( | ||
"Complete loading suggestions for library [{}].", | ||
msg.libraryName | ||
) | ||
if (notification.updates.nonEmpty) { | ||
clients.foreach { clientId => | ||
sessionRouter ! DeliverToJsonController(clientId, notification) | ||
} | ||
} | ||
case Failure(ex) => | ||
logger.error( | ||
"Error applying suggestion updates for loaded library [{}] ({})", | ||
msg.libraryName, | ||
ex.getMessage | ||
) | ||
} | ||
|
||
case msg: Api.SuggestionsDatabaseModuleUpdateNotification | ||
if state.isSuggestionUpdatesRunning => | ||
state.suggestionUpdatesQueue.enqueue(msg) | ||
|
||
case SuggestionUpdatesBatch(updates) if state.isSuggestionUpdatesRunning => | ||
state.suggestionUpdatesQueue.enqueueAll(updates) | ||
state.suggestionUpdatesQueue.prependAll(updates) | ||
|
||
case SuggestionUpdatesBatch(updates) => | ||
val modules = updates.map(_.module) | ||
|
@@ -493,6 +497,14 @@ final class SuggestionsHandler( | |
updates.foreach(sessionRouter ! _) | ||
context.become(initialized(name, graph, clients, state)) | ||
|
||
case libraryLoaded: Api.LibraryLoaded => | ||
logger.debug( | ||
"Loaded Library [{}.{}]", | ||
libraryLoaded.namespace, | ||
libraryLoaded.name | ||
) | ||
System.err.println("Loaded library: " + libraryLoaded.name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks spurious |
||
|
||
case SuggestionUpdatesCompleted => | ||
if (state.suggestionUpdatesQueue.nonEmpty) { | ||
self ! SuggestionUpdatesBatch(state.suggestionUpdatesQueue.removeAll()) | ||
|
@@ -515,17 +527,9 @@ final class SuggestionsHandler( | |
private def tryInitialize(state: SuggestionsHandler.Initialization): Unit = { | ||
logger.debug("Trying to initialize with state [{}]", state) | ||
state.initialized.fold(context.become(initializing(state))) { | ||
case (name, graph) => | ||
case (projectName, graph) => | ||
logger.debug("Initialized with state [{}].", state) | ||
val requestId = UUID.randomUUID() | ||
suggestionsRepo.getAllModules | ||
.map { modules => | ||
runtimeConnector ! Api.Request( | ||
requestId, | ||
Api.VerifyModulesIndexRequest(modules) | ||
) | ||
} | ||
context.become(verifying(name, graph)) | ||
context.become(initialized(projectName, graph, Set(), State())) | ||
unstashAll() | ||
} | ||
} | ||
|
@@ -543,6 +547,48 @@ final class SuggestionsHandler( | |
} | ||
} | ||
|
||
/** Handle the suggestions of the loaded library. | ||
* | ||
* Adds the new suggestions to the suggestions database and sends the | ||
* appropriate notification to the client. | ||
* | ||
* @param suggestions the loaded suggestions | ||
* @return the API suggestions database update notification | ||
*/ | ||
private def applyLoadedSuggestions( | ||
suggestions: Vector[Suggestion] | ||
): Future[SuggestionsDatabaseUpdateNotification] = { | ||
for { | ||
treeResults <- suggestionsRepo.applyTree( | ||
suggestions.map(Api.SuggestionUpdate(_, Api.SuggestionAction.Add())) | ||
) | ||
version <- suggestionsRepo.currentVersion | ||
} yield { | ||
val treeUpdates = treeResults.flatMap { | ||
case QueryResult(ids, Api.SuggestionUpdate(suggestion, action)) => | ||
val verb = action.getClass.getSimpleName | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be moved to the condition with the log using it? |
||
action match { | ||
case Api.SuggestionAction.Add() => | ||
if (ids.isEmpty) { | ||
logger.error("Cannot {} [{}].", verb, suggestion) | ||
} | ||
ids.map( | ||
SuggestionsDatabaseUpdate.Add( | ||
_, | ||
generateDocumentation(suggestion) | ||
) | ||
) | ||
case action => | ||
logger.error( | ||
s"Invalid action during suggestions loading [$action]." | ||
) | ||
Seq() | ||
} | ||
} | ||
SuggestionsDatabaseUpdateNotification(version, treeUpdates) | ||
} | ||
} | ||
|
||
/** Handle the suggestions database update. | ||
* | ||
* Function applies notification updates on the suggestions database and | ||
|
@@ -783,9 +829,6 @@ object SuggestionsHandler { | |
new ProjectNameUpdated(projectName, Seq()) | ||
} | ||
|
||
/** The notification that the suggestions database has been verified. */ | ||
case object Verified | ||
|
||
/** The notification that the suggestion updates are processed. */ | ||
case object SuggestionUpdatesCompleted | ||
|
||
|
@@ -843,7 +886,7 @@ object SuggestionsHandler { | |
* @param config the server configuration | ||
* @param contentRootManager the content root manager | ||
* @param suggestionsRepo the suggestions repo | ||
* @param fileVersionsRepo the file versions repo | ||
* @param versionsRepo the versions repo | ||
* @param sessionRouter the session router | ||
* @param runtimeConnector the runtime connector | ||
* @param docSectionsBuilder the builder of documentation sections | ||
|
@@ -852,7 +895,7 @@ object SuggestionsHandler { | |
config: Config, | ||
contentRootManager: ContentRootManager, | ||
suggestionsRepo: SuggestionsRepo[Future], | ||
fileVersionsRepo: VersionsRepo[Future], | ||
versionsRepo: VersionsRepo[Future], | ||
sessionRouter: ActorRef, | ||
runtimeConnector: ActorRef, | ||
docSectionsBuilder: DocSectionsBuilder = DocSectionsBuilder() | ||
|
@@ -862,7 +905,7 @@ object SuggestionsHandler { | |
config, | ||
contentRootManager, | ||
suggestionsRepo, | ||
fileVersionsRepo, | ||
versionsRepo, | ||
sessionRouter, | ||
runtimeConnector, | ||
docSectionsBuilder | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
package org.enso.languageserver.search | ||
|
||
import org.enso.docs.generator.DocsGenerator | ||
import org.enso.docs.sections.DocSectionsBuilder | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably unnecessary import. |
||
import org.enso.polyglot.Suggestion | ||
|
||
import java.util.UUID | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@4e6's idea is to deliver the cached
suggestion.json
here. However I haven't hit a breakpoint placed here yet. I am not sure who's supposed to deliver this message? Probably we are missing a call toNotificationHandler.addListener
that would registerSuggestionHandler
. Probably the listener shall be attached whencase InitializedEvent.TruffleContextInitialized
is delivered - by where can I find theEnsoContext
at that moment?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One has to subscribe to Akka event bus to get the notification - f480e03
But now there is another problem: The
SuggestionSerializationManager
is in runtime, while this code is inlanguage-server
- how shall these two talk to each other? I believe this "library added" notification is send from following stacktrace:I believe the next step is to modify code in
PackageRepository
to check whether a suggestion cache exists for the library. If it does, read it and send the content of the suggestions via theApi.LibraryLoaded
messages to the "language-server" project that can distribute it further. The following code shall be modified to send alsolibrarySuggestions
: