mirror of
https://github.com/enso-org/enso.git
synced 2024-11-27 02:55:06 +03:00
Fix for SQLite DB busy error on Azure (#1395)
depending on an environmental variable is used either default locking mode or a mode that uses flock syscall
This commit is contained in:
parent
3b48fc7e66
commit
d257615ef1
@ -0,0 +1,40 @@
|
||||
package org.enso.languageserver.boot
|
||||
|
||||
/** Signal where the lang. server is deployed.
|
||||
*/
|
||||
sealed trait DeploymentType
|
||||
|
||||
object DeploymentType {
|
||||
|
||||
/** Desktop deployment.
|
||||
*/
|
||||
case object Desktop extends DeploymentType
|
||||
|
||||
/** Azure deployment.
|
||||
*/
|
||||
case object Azure extends DeploymentType
|
||||
|
||||
/** Determines the current deployment type from environment variables.
|
||||
* @return the current deployment type
|
||||
*/
|
||||
def fromEnvironment(): DeploymentType = {
|
||||
if (sys.env.contains(DeploymentTypeVariableName)) {
|
||||
val value = sys.env(DeploymentTypeVariableName)
|
||||
fromString(value)
|
||||
} else {
|
||||
Desktop
|
||||
}
|
||||
}
|
||||
|
||||
/** Determines a current deployment type from a string value.
|
||||
* @return a deployment type
|
||||
*/
|
||||
def fromString(value: String): DeploymentType =
|
||||
value.toLowerCase.trim match {
|
||||
case "desktop" | "" => Desktop
|
||||
case "azure" => Azure
|
||||
}
|
||||
|
||||
private lazy val DeploymentTypeVariableName = "DEPLOYMENT_TYPE"
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import java.net.URI
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import org.enso.jsonrpc.JsonRpcServer
|
||||
import org.enso.languageserver.boot.DeploymentType.{Azure, Desktop}
|
||||
import org.enso.languageserver.capability.CapabilityRouter
|
||||
import org.enso.languageserver.data._
|
||||
import org.enso.languageserver.effect.ZioExec
|
||||
@ -34,6 +35,7 @@ import org.enso.languageserver.util.binary.BinaryEncoder
|
||||
import org.enso.loggingservice.{JavaLoggingLogHandler, LogLevel}
|
||||
import org.enso.polyglot.{LanguageInfo, RuntimeOptions, RuntimeServerInfo}
|
||||
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
||||
import org.enso.searcher.sqlite.LockingMode
|
||||
import org.enso.text.{ContentBasedVersioning, Sha3_224VersionCalculator}
|
||||
import org.graalvm.polyglot.Context
|
||||
import org.graalvm.polyglot.io.MessageEndpoint
|
||||
@ -84,7 +86,19 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
log.trace("Created ActorSystem")
|
||||
|
||||
val sqlDatabase =
|
||||
SqlDatabase(languageServerConfig.directories.suggestionsDatabaseFile)
|
||||
DeploymentType.fromEnvironment() match {
|
||||
case Desktop =>
|
||||
SqlDatabase(
|
||||
languageServerConfig.directories.suggestionsDatabaseFile.toString
|
||||
)
|
||||
|
||||
case Azure =>
|
||||
SqlDatabase(
|
||||
languageServerConfig.directories.suggestionsDatabaseFile.toString,
|
||||
Some(LockingMode.UnixFlock)
|
||||
)
|
||||
}
|
||||
|
||||
val suggestionsRepo = new SqlSuggestionsRepo(sqlDatabase)(system.dispatcher)
|
||||
val versionsRepo = new SqlVersionsRepo(sqlDatabase)(system.dispatcher)
|
||||
log.trace("Created SQL Repos")
|
||||
|
@ -19,11 +19,11 @@ import org.enso.languageserver.session.JsonSession
|
||||
import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
|
||||
import org.enso.polyglot.data.Tree
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.searcher.{FileVersionsRepo, SuggestionsRepo}
|
||||
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
||||
import org.enso.searcher.{FileVersionsRepo, SuggestionsRepo}
|
||||
import org.enso.testkit.RetrySpec
|
||||
import org.enso.text.{ContentVersion, Sha3_224VersionCalculator}
|
||||
import org.enso.text.editing.model.Position
|
||||
import org.enso.text.{ContentVersion, Sha3_224VersionCalculator}
|
||||
import org.scalatest.BeforeAndAfterAll
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpecLike
|
||||
@ -594,10 +594,12 @@ class SuggestionsHandlerSpec
|
||||
): Unit = {
|
||||
val testContentRoot = Files.createTempDirectory(null).toRealPath()
|
||||
sys.addShutdownHook(FileUtils.deleteQuietly(testContentRoot.toFile))
|
||||
val config = newConfig(testContentRoot.toFile)
|
||||
val router = TestProbe("session-router")
|
||||
val connector = TestProbe("runtime-connector")
|
||||
val sqlDatabase = SqlDatabase(config.directories.suggestionsDatabaseFile)
|
||||
val config = newConfig(testContentRoot.toFile)
|
||||
val router = TestProbe("session-router")
|
||||
val connector = TestProbe("runtime-connector")
|
||||
val sqlDatabase = SqlDatabase(
|
||||
config.directories.suggestionsDatabaseFile.toString
|
||||
)
|
||||
val suggestionsRepo = new SqlSuggestionsRepo(sqlDatabase)
|
||||
val versionsRepo = new SqlVersionsRepo(sqlDatabase)
|
||||
val handler = newSuggestionsHandler(
|
||||
|
@ -81,13 +81,13 @@ class BaseServerTest extends JsonRpcServerTestKit {
|
||||
InputRedirectionController.props(stdIn, stdInSink, sessionRouter)
|
||||
)
|
||||
|
||||
val zioExec = ZioExec(zio.Runtime.default)
|
||||
val sqlDatabase =
|
||||
SqlDatabase(config.directories.suggestionsDatabaseFile.toString)
|
||||
val suggestionsRepo = new SqlSuggestionsRepo(sqlDatabase)(system.dispatcher)
|
||||
val versionsRepo = new SqlVersionsRepo(sqlDatabase)(system.dispatcher)
|
||||
|
||||
override def clientControllerFactory: ClientControllerFactory = {
|
||||
|
||||
val zioExec = ZioExec(zio.Runtime.default)
|
||||
val sqlDatabase = SqlDatabase(config.directories.suggestionsDatabaseFile)
|
||||
val suggestionsRepo = new SqlSuggestionsRepo(sqlDatabase)(system.dispatcher)
|
||||
val versionsRepo = new SqlVersionsRepo(sqlDatabase)(system.dispatcher)
|
||||
|
||||
val fileManager =
|
||||
system.actorOf(FileManager.props(config, new FileSystem, zioExec))
|
||||
val bufferRegistry =
|
||||
|
@ -4,6 +4,7 @@ searcher {
|
||||
driver = "org.sqlite.JDBC"
|
||||
connectionPool = disabled
|
||||
properties.journal_mode = "wal"
|
||||
properties.locking_mode = "EXCLUSIVE"
|
||||
numThreads = 1
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
package org.enso.searcher.sql
|
||||
|
||||
import java.io.File
|
||||
|
||||
import com.typesafe.config.{Config, ConfigFactory}
|
||||
import org.enso.searcher.Database
|
||||
import org.enso.searcher.sqlite.LockingMode
|
||||
import slick.dbio.DBIO
|
||||
import slick.jdbc.SQLiteProfile
|
||||
import slick.jdbc.SQLiteProfile.api._
|
||||
@ -43,24 +42,31 @@ object SqlDatabase {
|
||||
* @param filename the database file path
|
||||
* @return new sql database instance
|
||||
*/
|
||||
def apply(filename: File): SqlDatabase =
|
||||
apply(filename.toString)
|
||||
|
||||
/** Create [[SqlDatabase]] instance.
|
||||
*
|
||||
* @param filename the database file path
|
||||
* @return new sql database instance
|
||||
*/
|
||||
def apply(filename: String): SqlDatabase = {
|
||||
def apply(
|
||||
filename: String,
|
||||
maybeLockingMode: Option[LockingMode] = None
|
||||
): SqlDatabase = {
|
||||
val config = ConfigFactory
|
||||
.parseString(s"""$configPath.url = "${jdbcUrl(filename)}"""")
|
||||
.parseString(
|
||||
s"""$configPath.url = "${jdbcUrl(filename, maybeLockingMode)}""""
|
||||
)
|
||||
.withFallback(ConfigFactory.load())
|
||||
new SqlDatabase(Some(config))
|
||||
}
|
||||
|
||||
/** Create JDBC URL from the file path. */
|
||||
private def jdbcUrl(filename: String): String =
|
||||
s"jdbc:sqlite:${escapePath(filename)}"
|
||||
private def jdbcUrl(
|
||||
filename: String,
|
||||
maybeLockingMode: Option[LockingMode]
|
||||
): String = {
|
||||
maybeLockingMode match {
|
||||
case None =>
|
||||
s"jdbc:sqlite:${escapePath(filename)}"
|
||||
|
||||
case Some(lockingMode) =>
|
||||
s"jdbc:sqlite:file:${escapePath(filename)}?vfs=${lockingMode.name}"
|
||||
}
|
||||
}
|
||||
|
||||
/** Escape Windows path. */
|
||||
private def escapePath(path: String): String =
|
||||
|
@ -0,0 +1,24 @@
|
||||
package org.enso.searcher.sqlite
|
||||
|
||||
/** A mode used to handle file locking in SQLite */
|
||||
case class LockingMode private (name: String)
|
||||
|
||||
object LockingMode {
|
||||
|
||||
/** Default mode that uses POSIX advisory locks.
|
||||
*/
|
||||
val UnixPosix = LockingMode("unix")
|
||||
|
||||
/** It obtains and holds an exclusive lock on database files,
|
||||
* preventing other processes from accessing the database.
|
||||
* It uses the `flock` system call.
|
||||
*/
|
||||
val UnixFlock = LockingMode("unix-excl")
|
||||
|
||||
/** It uses dot-file locking rather than POSIX advisory locks. */
|
||||
val UnixDotFile = LockingMode("unix-dotfile")
|
||||
|
||||
/** All file locking operations are no-ops. */
|
||||
val UnixNone = LockingMode("unix-none")
|
||||
|
||||
}
|
@ -11,9 +11,9 @@ ADD runtime.jar /opt/enso/runtime.jar
|
||||
RUN chown -hR enso:enso /opt/enso
|
||||
RUN chmod -R u=rX,g=rX /opt/enso
|
||||
|
||||
RUN mkdir -p /home/enso/workspace
|
||||
RUN chown -hR enso:enso /home/enso/workspace
|
||||
RUN chmod -R u=rwX,g=rwX /home/enso/workspace
|
||||
RUN mkdir -p /volumes
|
||||
RUN chown -hR enso:enso /volumes
|
||||
RUN chmod -R u=rwX,g=rwX /volumes
|
||||
|
||||
USER enso:enso
|
||||
|
||||
@ -24,7 +24,6 @@ ENTRYPOINT ["java", "-jar", "-Dtruffle.class.path.append=runtime.jar", "-Dpolyg
|
||||
EXPOSE 30001
|
||||
EXPOSE 30002
|
||||
|
||||
VOLUME /home/enso/workspace
|
||||
|
||||
CMD ["--server", "--rpc-port", "30001", "--data-port", "30002", "--root-id", "00000000-0000-0000-0000-000000000001", "--path", "/home/enso/workspace", "--interface", "0.0.0.0"]
|
||||
VOLUME /volumes/workspace
|
||||
|
||||
CMD ["--server", "--daemon", "--rpc-port", "30001", "--data-port", "30002", "--root-id", "00000000-0000-0000-0000-000000000001", "--path", "/volumes/workspace", "--interface", "0.0.0.0", "--log-level", "INFO"]
|
||||
|
Loading…
Reference in New Issue
Block a user