blob: 4d286e336269d99bea6f73aba2b40a885b9cbe78 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.server;
16
tomlua155b532017-11-08 20:12:47 +010017import com.google.common.base.Preconditions;
janakrc3bcb982020-04-14 06:50:08 -070018import com.google.common.flogger.GoogleLogger;
ulfjack2602a172018-11-05 07:39:43 -080019import com.google.common.util.concurrent.ThreadFactoryBuilder;
Nathan Harmatad4803012015-09-08 20:03:22 +000020import com.google.devtools.build.lib.profiler.AutoProfiler;
janakr30e99152020-04-03 08:01:25 -070021import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
Benjamin Petersonf05c0a42018-08-08 05:29:34 -070022import com.google.devtools.build.lib.util.StringUtilities;
23import java.lang.management.ManagementFactory;
24import java.lang.management.MemoryMXBean;
25import java.lang.management.MemoryUsage;
Googler78cae6d2017-01-24 23:07:40 +000026import java.util.concurrent.Future;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import java.util.concurrent.ScheduledThreadPoolExecutor;
28import java.util.concurrent.TimeUnit;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029
30/**
31 * Run cleanup-related tasks during idle periods in the server.
32 * idle() and busy() must be called in that order, and only once.
33 */
34class IdleServerTasks {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035 private final ScheduledThreadPoolExecutor executor;
janakrc3bcb982020-04-14 06:50:08 -070036 private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037
Benjamin Petersonf05c0a42018-08-08 05:29:34 -070038 /** Must be called from the main thread. */
lberkid9b10822018-04-03 03:17:21 -070039 public IdleServerTasks() {
ulfjack2602a172018-11-05 07:39:43 -080040 this.executor = new ScheduledThreadPoolExecutor(
41 1,
42 new ThreadFactoryBuilder().setNameFormat("idle-server-tasks-%d").build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043 }
44
45 /**
46 * Called when the server becomes idle. Should not block, but may invoke
47 * new threads.
48 */
49 public void idle() {
50 Preconditions.checkState(!executor.isShutdown());
51
lberki97abb522017-09-04 18:51:57 +020052 @SuppressWarnings("unused")
Googler78cae6d2017-01-24 23:07:40 +000053 Future<?> possiblyIgnoredError =
lberki97abb522017-09-04 18:51:57 +020054 executor.schedule(
55 () -> {
Benjamin Petersonf05c0a42018-08-08 05:29:34 -070056 MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
57 MemoryUsage before = memBean.getHeapMemoryUsage();
janakr30e99152020-04-03 08:01:25 -070058 try (AutoProfiler p = GoogleAutoProfilerUtils.logged("Idle GC")) {
lberki8981f7e2017-06-29 11:48:10 +020059 System.gc();
Googler78cae6d2017-01-24 23:07:40 +000060 }
Benjamin Petersonf05c0a42018-08-08 05:29:34 -070061 MemoryUsage after = memBean.getHeapMemoryUsage();
janakrc3bcb982020-04-14 06:50:08 -070062 logger.atInfo().log(
63 "[Idle GC] used: %s -> %s, committed: %s -> %s",
64 StringUtilities.prettyPrintBytes(before.getUsed()),
65 StringUtilities.prettyPrintBytes(after.getUsed()),
66 StringUtilities.prettyPrintBytes(before.getCommitted()),
67 StringUtilities.prettyPrintBytes(after.getCommitted()));
Googler78cae6d2017-01-24 23:07:40 +000068 },
69 10,
70 TimeUnit.SECONDS);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071 }
72
73 /**
74 * Called by the main thread when the server gets to work.
75 * Should return quickly.
76 */
77 public void busy() {
78 Preconditions.checkState(!executor.isShutdown());
79
80 // Make sure tasks are finished after shutdown(), so they do not intefere
81 // with subsequent server invocations.
82 executor.shutdown();
83 executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
84 executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
85
86 boolean interrupted = false;
87 while (true) {
88 try {
89 executor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS);
90 break;
91 } catch (InterruptedException e) {
92 // It's unsafe to leak threads - just reset the interrupt bit later.
93 interrupted = true;
94 }
95 }
96
97 if (interrupted) {
98 Thread.currentThread().interrupt();
99 }
100 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101}