From 83860523a72f068a5eebd9932bda357709b9784e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 20 Feb 2014 01:29:42 +0100 Subject: [PATCH] synchronizing filesystem component and making open/read/seek/close limited direct calls, reduced default max read buffer in turn. this should give better performance when reading many small files; made fs.close direct without limit to get rid of the ugly file handle gc workaround involving a timer --- .../cil/oc/server/component/FileSystem.scala | 50 ++++++++++--------- .../opencomputers/lua/rom/lib/filesystem.lua | 13 +---- .../opencomputers/lua/rom/lib/package.lua | 1 - src/main/resources/reference.conf | 2 +- 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/main/java/li/cil/oc/server/component/FileSystem.scala b/src/main/java/li/cil/oc/server/component/FileSystem.scala index f743985bb..282f4ceae 100644 --- a/src/main/java/li/cil/oc/server/component/FileSystem.scala +++ b/src/main/java/li/cil/oc/server/component/FileSystem.scala @@ -20,13 +20,15 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC // ----------------------------------------------------------------------- // @Callback(direct = true) - def getLabel(context: Context, args: Arguments): Array[AnyRef] = label match { - case value: Label => result(label.getLabel) - case _ => null + def getLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { + label match { + case value: Label => result(label.getLabel) + case _ => null + } } @Callback - def setLabel(context: Context, args: Arguments): Array[AnyRef] = { + def setLabel(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { if (label == null) throw new Exception("filesystem does not support labeling") if (args.checkAny(0) == null) label.setLabel(null) else label.setLabel(args.checkString(0)) @@ -34,12 +36,12 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } @Callback(direct = true) - def isReadOnly(context: Context, args: Arguments): Array[AnyRef] = { + def isReadOnly(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.isReadOnly) } @Callback(direct = true) - def spaceTotal(context: Context, args: Arguments): Array[AnyRef] = { + def spaceTotal(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val space = fileSystem.spaceTotal if (space < 0) Array("unlimited") @@ -48,32 +50,32 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } @Callback(direct = true) - def spaceUsed(context: Context, args: Arguments): Array[AnyRef] = { + def spaceUsed(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.spaceUsed) } @Callback(direct = true) - def exists(context: Context, args: Arguments): Array[AnyRef] = { + def exists(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.exists(clean(args.checkString(0)))) } @Callback(direct = true) - def size(context: Context, args: Arguments): Array[AnyRef] = { + def size(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.size(clean(args.checkString(0)))) } @Callback(direct = true) - def isDirectory(context: Context, args: Arguments): Array[AnyRef] = { + def isDirectory(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.isDirectory(clean(args.checkString(0)))) } @Callback(direct = true) - def lastModified(context: Context, args: Arguments): Array[AnyRef] = { + def lastModified(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.lastModified(clean(args.checkString(0)))) } @Callback - def list(context: Context, args: Arguments): Array[AnyRef] = { + def list(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { Option(fileSystem.list(clean(args.checkString(0)))) match { case Some(list) => Array(list) case _ => null @@ -81,26 +83,26 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } @Callback - def makeDirectory(context: Context, args: Arguments): Array[AnyRef] = { + def makeDirectory(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def recurse(path: String): Boolean = !fileSystem.exists(path) && (fileSystem.makeDirectory(path) || (recurse(path.split("/").dropRight(1).mkString("/")) && fileSystem.makeDirectory(path))) result(recurse(clean(args.checkString(0)))) } @Callback - def remove(context: Context, args: Arguments): Array[AnyRef] = { + def remove(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { def recurse(parent: String): Boolean = (!fileSystem.isDirectory(parent) || fileSystem.list(parent).forall(child => recurse(parent + "/" + child))) && fileSystem.delete(parent) result(recurse(clean(args.checkString(0)))) } @Callback - def rename(context: Context, args: Arguments): Array[AnyRef] = { + def rename(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { result(fileSystem.rename(clean(args.checkString(0)), clean(args.checkString(1)))) } - @Callback - def close(context: Context, args: Arguments): Array[AnyRef] = { + @Callback(direct = true) + def close(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) Option(fileSystem.getHandle(handle)) match { case Some(file) => @@ -113,8 +115,8 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC null } - @Callback - def open(context: Context, args: Arguments): Array[AnyRef] = { + @Callback(direct = true, limit = 4) + def open(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { if (owners.get(context.node.address).fold(false)(_.size >= Settings.get.maxHandles)) { throw new IOException("too many open handles") } @@ -127,8 +129,8 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC result(handle) } - @Callback - def read(context: Context, args: Arguments): Array[AnyRef] = { + @Callback(direct = true, limit = 4) + def read(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1))) checkOwner(context.node.address, handle) @@ -158,8 +160,8 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } } - @Callback - def seek(context: Context, args: Arguments): Array[AnyRef] = { + @Callback(direct = true, limit = 4) + def seek(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val whence = args.checkString(1) val offset = args.checkInteger(2) @@ -178,7 +180,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC } @Callback - def write(context: Context, args: Arguments): Array[AnyRef] = { + def write(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val value = args.checkByteArray(1) if (!node.tryChangeBuffer(-Settings.get.hddWriteCost * value.length)) { diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/filesystem.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/filesystem.lua index 8914c91ff..665040d35 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/filesystem.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/filesystem.lua @@ -3,7 +3,7 @@ local unicode = require("unicode") local filesystem, fileStream = {}, {} local isAutorunEnabled = true -local mtab = {children={}, links={}} +local mtab = {name="", children={}, links={}} local function segments(path) path = path:gsub("\\", "/") @@ -472,18 +472,9 @@ function filesystem.open(path, mode) local stream = {fs = node.fs, handle = handle} - -- stream:close does a syscall, which yields, and that's not possible in - -- the __gc metamethod. So we start a timer to do the yield/cleanup. local function cleanup(self) if not self.handle then return end - -- save non-gc'ed values as upvalues - local fs = self.fs - local handle = self.handle - local function close() - fs.close(handle) - end - -- Required locally because this is a bootstrapped file. - require("event").timer(0, close) + self.fs.close(self.handle) end local metatable = {__index = fileStream, __gc = cleanup, diff --git a/src/main/resources/assets/opencomputers/lua/rom/lib/package.lua b/src/main/resources/assets/opencomputers/lua/rom/lib/package.lua index d97ac8bb4..8f4bbd1d3 100644 --- a/src/main/resources/assets/opencomputers/lua/rom/lib/package.lua +++ b/src/main/resources/assets/opencomputers/lua/rom/lib/package.lua @@ -8,7 +8,6 @@ local loaded = { ["_G"] = _G, ["bit32"] = bit32, ["coroutine"] = coroutine, - ["io"] = io, ["math"] = math, ["os"] = os, ["package"] = package, diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index d0bf6a74c..cb2bf7eff 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -588,7 +588,7 @@ opencomputers { # allocations regardless of the amount of RAM installed in the computer it # runs on. As a side effect this pretty much determines the read # performance of file systems. - maxReadBuffer: 8192 + maxReadBuffer: 2048 } # Internet settings, security related.