Skip to content

Commit 6ad4d0e

Browse files
Merge pull request #55 from alexarchambault/truncate-file-option
Allow to have the server truncate file periodically
2 parents c58e27e + 78faa5c commit 6ad4d0e

File tree

1 file changed

+81
-22
lines changed

1 file changed

+81
-22
lines changed

frontend/src/main/scala/bloop/Bloop.scala

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,28 @@ package bloop
22

33
import java.net.InetAddress
44

5-
import bloop.logging.BloopLogger
6-
import bloop.logging.Logger
5+
import bloop.logging.{BloopLogger, Logger}
76
import bloop.util.ProxySetup
87

9-
import java.io.InputStream
10-
import java.io.PrintStream
11-
import java.nio.channels.ReadableByteChannel
12-
import java.nio.file.Files
13-
import java.nio.file.Paths
14-
import java.util.concurrent.atomic.AtomicBoolean
8+
import java.io.{File, InputStream, OutputStream, PrintStream}
9+
import java.net.{ServerSocket, Socket, SocketAddress}
10+
import java.nio.ByteBuffer
11+
import java.nio.channels.{Channels, ReadableByteChannel, SeekableByteChannel}
12+
import java.nio.file.attribute.PosixFilePermissions
13+
import java.nio.file.{Files, Path, Paths, StandardOpenOption}
14+
import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger}
15+
import java.util.concurrent.{Executors, ThreadFactory, TimeUnit}
1516

16-
import com.martiansoftware.nailgun.NGListeningAddress
17-
import com.martiansoftware.nailgun.NGConstants
17+
import com.martiansoftware.nailgun.{NGConstants, NGListeningAddress}
1818
import com.martiansoftware.nailgun.{Alias, NGContext, NGServer}
1919
import libdaemonjvm._
2020
import libdaemonjvm.internal.{LockProcess, SocketHandler}
2121
import libdaemonjvm.server._
2222

23-
import scala.util.Properties
24-
import scala.util.Try
25-
import java.net.ServerSocket
26-
import java.net.Socket
27-
import java.io.OutputStream
28-
import java.net.SocketAddress
29-
import java.nio.channels.Channels
30-
import java.nio.ByteBuffer
31-
import java.io.File
23+
import scala.concurrent.duration.DurationInt
24+
import scala.util.{Properties, Try}
25+
3226
import org.slf4j
33-
import java.nio.file.attribute.PosixFilePermissions
34-
import java.nio.file.Path
3527
import sun.misc.{Signal, SignalHandler}
3628

3729
sealed abstract class Bloop
@@ -68,8 +60,18 @@ object Bloop {
6860
)
6961
}
7062

71-
if (java.lang.Boolean.getBoolean("bloop.ignore-sig-int"))
63+
val pid = ProcessHandle.current().pid()
64+
System.err.println(s"Bloop server PID: $pid")
65+
66+
if (java.lang.Boolean.getBoolean("bloop.ignore-sig-int")) {
67+
System.err.println("Ignoring SIGINT")
7268
ignoreSigint()
69+
}
70+
71+
for (value <- sys.props.get("bloop.truncate-output-file-periodically")) {
72+
System.err.println(s"Will truncate output file $value every 5 minutes")
73+
truncateFilePeriodically(Paths.get(value))
74+
}
7375

7476
lockFilesOrHostPort match {
7577
case Left(hostPort) =>
@@ -94,6 +96,63 @@ object Bloop {
9496
()
9597
}
9698

99+
private def truncateFilePeriodically(file: Path): Unit = {
100+
val scheduler = Executors.newSingleThreadScheduledExecutor(
101+
new ThreadFactory {
102+
val count = new AtomicInteger
103+
def newThread(r: Runnable): Thread = {
104+
val t = new Thread(r, s"truncate-file-${count.incrementAndGet()}")
105+
t.setDaemon(true)
106+
t
107+
}
108+
}
109+
)
110+
val period = 5.minutes
111+
val maxSize = 1024 * 1024 // 1 MiB
112+
val runnable: Runnable =
113+
() =>
114+
try {
115+
if (Files.exists(file)) {
116+
val size = Files.size(file)
117+
if (size > maxSize) {
118+
var bc: SeekableByteChannel = null
119+
try {
120+
bc = Files.newByteChannel(file, StandardOpenOption.WRITE)
121+
bc.truncate(0L)
122+
} finally {
123+
if (bc != null)
124+
bc.close()
125+
}
126+
127+
// Seems closing / re-opening the output file is needed for truncation to work
128+
val ps = new PrintStream(Files.newOutputStream(file))
129+
val formerOut = System.out
130+
val formerErr = System.err
131+
System.setOut(ps)
132+
System.setErr(ps)
133+
formerOut.close()
134+
formerErr.close()
135+
136+
System.err.println(s"Truncated $file (former size: $size B)")
137+
()
138+
}
139+
}
140+
} catch {
141+
case t: Throwable =>
142+
System.err.println(
143+
s"Caught $t while checking if $file needs to be truncated, ignoring it"
144+
)
145+
t.printStackTrace(System.err)
146+
}
147+
scheduler.scheduleAtFixedRate(
148+
runnable,
149+
period.length,
150+
period.length,
151+
period.unit
152+
)
153+
()
154+
}
155+
97156
def startServer(socketPathsOrHostPort: Either[(InetAddress, Int), SocketPaths]): Unit = {
98157
val socketAndPathOrHostPort = socketPathsOrHostPort.map { socketPaths =>
99158
val socket = libdaemonjvm.Util.serverSocketFromChannel(

0 commit comments

Comments
 (0)