-
Notifications
You must be signed in to change notification settings - Fork 279
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PlatformFileOps: read/write files asynchronously
Previously, we simply wrapped a Future around a blocking file I/O both on JVM and Native; while we still keep this approach on Native, let's implement actual asynchronous file I/O on JVM, just like on JS. Also, modify runners to use this async writing and a different thread pool for that, so that it does not clash with formatting tasks.
- Loading branch information
Showing
12 changed files
with
198 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
scalafmt-sysops/jvm/src/main/scala/org/scalafmt/sysops/GranularPlatformAsyncOps.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package org.scalafmt.sysops | ||
|
||
import java.io.ByteArrayOutputStream | ||
import java.nio.ByteBuffer | ||
import java.nio.channels.AsynchronousFileChannel | ||
import java.nio.channels.CompletionHandler | ||
import java.nio.file.Path | ||
import java.nio.file.StandardOpenOption | ||
import java.util.concurrent.Executors | ||
|
||
import scala.concurrent.ExecutionContext | ||
import scala.concurrent.Future | ||
import scala.concurrent.Promise | ||
import scala.io.Codec | ||
import scala.util.Try | ||
|
||
private[sysops] object GranularPlatformAsyncOps { | ||
|
||
implicit val ioExecutionContext: ExecutionContext = ExecutionContext | ||
.fromExecutor(Executors.newCachedThreadPool()) | ||
|
||
def readFileAsync(path: Path)(implicit codec: Codec): Future[String] = { | ||
val promise = Promise[String]() | ||
|
||
val buf = new Array[Byte](1024) | ||
val bbuf = ByteBuffer.wrap(buf) | ||
val os = new ByteArrayOutputStream() | ||
|
||
Try { | ||
val channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ) | ||
val handler = new CompletionHandler[Integer, AnyRef] { | ||
override def completed(result: Integer, unused: AnyRef): Unit = { | ||
val count = result.intValue() | ||
if (count < 0) { | ||
promise.trySuccess(os.toString(codec.charSet.name())) | ||
channel.close() | ||
} else { | ||
if (count > 0) { | ||
os.write(buf, 0, count) | ||
bbuf.clear() | ||
} | ||
channel.read(bbuf, os.size(), null, this) | ||
} | ||
} | ||
override def failed(exc: Throwable, unused: AnyRef): Unit = { | ||
promise.tryFailure(exc) | ||
channel.close() | ||
} | ||
} | ||
|
||
channel.read(bbuf, 0, null, handler) | ||
}.failed.foreach(promise.tryFailure) | ||
|
||
promise.future | ||
} | ||
|
||
def writeFileAsync(path: Path, content: String)(implicit | ||
codec: Codec, | ||
): Future[Unit] = { | ||
val promise = Promise[Unit]() | ||
val buf = ByteBuffer.wrap(content.getBytes(codec.charSet)) | ||
|
||
Try { | ||
val channel = AsynchronousFileChannel.open( | ||
path, | ||
StandardOpenOption.CREATE, | ||
StandardOpenOption.WRITE, | ||
StandardOpenOption.TRUNCATE_EXISTING, | ||
) | ||
|
||
val handler = new CompletionHandler[Integer, AnyRef] { | ||
override def completed(result: Integer, attachment: AnyRef): Unit = | ||
if (buf.hasRemaining) channel.write(buf, buf.position(), null, this) | ||
else { | ||
promise.trySuccess(()) | ||
channel.close() | ||
} | ||
|
||
override def failed(exc: Throwable, attachment: AnyRef): Unit = { | ||
promise.tryFailure(exc) | ||
channel.close() | ||
} | ||
} | ||
|
||
channel.write(buf, 0L, null, handler) | ||
}.failed.foreach(promise.tryFailure) | ||
|
||
promise.future | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
scalafmt-sysops/native/src/main/scala/org/scalafmt/sysops/GranularPlatformAsyncOps.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package org.scalafmt.sysops | ||
|
||
import java.nio.file.Files | ||
import java.nio.file.Path | ||
|
||
import scala.concurrent.ExecutionContext | ||
import scala.concurrent.Future | ||
import scala.io.Codec | ||
|
||
private[sysops] object GranularPlatformAsyncOps { | ||
|
||
import PlatformRunOps.executionContext | ||
|
||
def ioExecutionContext: ExecutionContext = executionContext | ||
|
||
def readFileAsync(path: Path)(implicit codec: Codec): Future[String] = | ||
Future(PlatformFileOps.readFile(path)) | ||
|
||
def writeFileAsync(path: Path, content: String)(implicit | ||
codec: Codec, | ||
): Future[Unit] = Future { | ||
val bytes = content.getBytes(codec.charSet) | ||
Files.write(path, bytes) | ||
} | ||
|
||
} |
Oops, something went wrong.