Skip to content

Commit 5dfc005

Browse files
authored
Merge pull request #19058 from JasonFengJ9/attachapiaccessfiles-v0.44
(0.44.0) AttachAPI updates control file access time for long running applications
2 parents 7c701a7 + 3abb8f0 commit 5dfc005

File tree

3 files changed

+163
-21
lines changed

3 files changed

+163
-21
lines changed

jcl/src/java.base/share/classes/openj9/internal/tools/attach/target/AttachHandler.java

Lines changed: 152 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@
3131
import java.io.File;
3232
import java.io.IOException;
3333
import java.io.PrintStream;
34+
import java.nio.file.Files;
35+
import java.nio.file.Paths;
36+
import java.nio.file.attribute.FileTime;
3437
import java.util.Properties;
3538
import java.util.Vector;
39+
import java.util.concurrent.TimeUnit;
3640

3741
/**
3842
* This class handles incoming attachment requests from other VMs. Must be
@@ -54,7 +58,7 @@ public class AttachHandler extends Thread {
5458
/**
5559
* Time delay before we give up trying to terminate the wait loop.
5660
*/
57-
static final long shutdownTimeoutMs = Integer.getInteger("com.ibm.tools.attach.shutdown_timeout", 10000).longValue(); //$NON-NLS-1$
61+
static final long shutdownTimeoutMs = Long.getLong("com.ibm.tools.attach.shutdown_timeout", 10000).longValue(); //$NON-NLS-1$
5862
private enum AttachStateValues {
5963
ATTACH_UNINITIALIZED, ATTACH_TERMINATED, ATTACH_STARTING, ATTACH_INITIALIZED
6064
}
@@ -118,6 +122,8 @@ static final class syncObject {
118122
/* [PR Jazz 30075] Make syncFileLock an instance variable since it is accessed only by the attachHandler singleton. */
119123
FileLock syncFileLock;
120124

125+
static volatile Thread fileAccessTimeUpdaterThread;
126+
121127
/**
122128
* Keep the constructor private
123129
*/
@@ -323,10 +329,91 @@ private boolean initialize() throws IOException {
323329
syncFileLock = new FileLock(syncFileObjectTemp.getAbsolutePath(), TargetDirectory.SYNC_FILE_PERMISSIONS);
324330
/* give other users read permission to the sync file */
325331

332+
if (IPC.isLinux) {
333+
// Update AttachAPI control file access time every sleepDays (8 days by default).
334+
// This is to prevent Linux systemd from deleting the aging files within /tmp after 10 days.
335+
// More details at https://github.com/eclipse-openj9/openj9/issues/18720
336+
int sleepDays = 8;
337+
String fileAccessUpdateTime = internalProperties.getProperty("com.ibm.tools.attach.fileAccessUpdateTime", "8"); //$NON-NLS-1$ //$NON-NLS-2$
338+
IPC.logMessage("fileAccessUpdateTime = " + fileAccessUpdateTime); //$NON-NLS-1$
339+
try {
340+
sleepDays = Integer.parseInt(fileAccessUpdateTime);
341+
} catch (NumberFormatException nfe) {
342+
// ignore this non-fatal exception, and use the default value
343+
}
344+
IPC.logMessage("fileAccessTimeUpdaterThread sleepDays = " + sleepDays); //$NON-NLS-1$
345+
if (sleepDays > 0) {
346+
final long targetIntervalMillis = TimeUnit.DAYS.toMillis(sleepDays);
347+
final String lastAccessTime = "lastAccessTime"; //$NON-NLS-1$
348+
final String commonDir = CommonDirectory.getCommonDirFileObject().getPath();
349+
fileAccessTimeUpdaterThread = new Thread("Attach API update file access time") { //$NON-NLS-1$
350+
@Override
351+
public void run() {
352+
VM.markCurrentThreadAsSystem();
353+
354+
long lastMillis = System.currentTimeMillis();
355+
long sleepMillis = targetIntervalMillis;
356+
for (;;) {
357+
try {
358+
Thread.sleep(sleepMillis);
359+
} catch (InterruptedException ie) {
360+
// ignore this non-fatal exception
361+
IPC.logMessage("fileAccessTimeUpdaterThread received an InterruptedException: " + ie.getMessage()); //$NON-NLS-1$
362+
}
363+
if (isAttachApiTerminated()) {
364+
IPC.logMessage("AttachAPI was terminated, fileAccessTimeUpdaterThread exits"); //$NON-NLS-1$
365+
break;
366+
}
367+
long currentMillis = System.currentTimeMillis();
368+
long passedMillis = currentMillis - lastMillis;
369+
if (passedMillis >= sleepMillis) {
370+
FileTime fileTime = FileTime.fromMillis(currentMillis);
371+
IPC.logMessage("fileAccessTimeUpdaterThread currentMillis = " + currentMillis); //$NON-NLS-1$
372+
try {
373+
// Common directory : _attachlock
374+
File attachLock = new File(commonDir, CommonDirectory.ATTACH_LOCK);
375+
if (attachLock.exists()) {
376+
// _attachlock only appears when there was an attaching request
377+
Files.setAttribute(Paths.get(attachLock.getPath()), lastAccessTime, fileTime);
378+
IPC.logMessage("fileAccessTimeUpdaterThread updated access time = " + attachLock); //$NON-NLS-1$
379+
}
380+
// Common directory : _controller
381+
Files.setAttribute(Paths.get(commonDir, CommonDirectory.CONTROLLER_LOCKFILE), lastAccessTime, fileTime);
382+
// Common directory : _notifier
383+
Files.setAttribute(Paths.get(commonDir, CommonDirectory.CONTROLLER_NOTIFIER), lastAccessTime, fileTime);
384+
// Target directory : attachNotificationSync
385+
Files.setAttribute(Paths.get(TargetDirectory.getSyncFileObject().getPath()), lastAccessTime, fileTime);
386+
// Target directory : attachInfo
387+
Files.setAttribute(Paths.get(TargetDirectory.getAdvertisementFileObject().getPath()), lastAccessTime, fileTime);
388+
} catch (IOException ioe) {
389+
// ignore this non-fatal exception
390+
IPC.logMessage("fileAccessTimeUpdaterThread received an IOException : " + ioe.getMessage()); //$NON-NLS-1$
391+
}
392+
// reset for next update
393+
sleepMillis = targetIntervalMillis;
394+
lastMillis = currentMillis;
395+
} else {
396+
// continue sleep()
397+
sleepMillis = targetIntervalMillis - passedMillis;
398+
IPC.logMessage("fileAccessTimeUpdaterThread currentMillis = " + currentMillis //$NON-NLS-1$
399+
+ ", passedMillis = " + passedMillis //$NON-NLS-1$
400+
+ ", sleepMillis = " + sleepMillis); //$NON-NLS-1$
401+
}
402+
}
403+
}
404+
};
405+
fileAccessTimeUpdaterThread.setDaemon(true);
406+
if (isAttachApiTerminated()) {
407+
IPC.logMessage("AttachAPI was already terminated, no need to start fileAccessTimeUpdaterThread"); //$NON-NLS-1$
408+
return false;
409+
}
410+
fileAccessTimeUpdaterThread.start();
411+
}
412+
}
413+
326414
return true;
327415
}
328416

329-
330417
/**
331418
* Try to read the reply. If it exists, connect to the attacher. This may be called from tryAttachTarget() in the case
332419
* of a VM attaching to itself.
@@ -372,7 +459,6 @@ public void attachSelf(int portNumber, String key) {
372459
* @return true if the caller should destroy the semaphore
373460
*/
374461
protected boolean terminate(boolean wakeHandler) {
375-
376462
if (LOGGING_DISABLED != loggingStatus) {
377463
IPC.logMessage("AttachHandler terminate: Attach API is being shut down, currentAttachThread = " + currentAttachThread); //$NON-NLS-1$
378464
}
@@ -391,7 +477,12 @@ protected boolean terminate(boolean wakeHandler) {
391477
break;
392478
}
393479
}
394-
currentAttachThread.interrupt(); /* do this after we change the attachState */
480+
/* do this after we change the attachState */
481+
if ((fileAccessTimeUpdaterThread != null) && fileAccessTimeUpdaterThread.isAlive()) {
482+
IPC.logMessage("fileAccessTimeUpdaterThread interrupt"); //$NON-NLS-1$
483+
fileAccessTimeUpdaterThread.interrupt();
484+
}
485+
currentAttachThread.interrupt();
395486
if (wakeHandler) {
396487
if (LOGGING_DISABLED != loggingStatus) {
397488
IPC.logMessage("AttachHandler terminate removing contents of directory : ", TargetDirectory.getTargetDirectoryPath(getVmId())); //$NON-NLS-1$
@@ -522,6 +613,55 @@ static final class teardownHook extends Thread {
522613
super("Attach API teardown"); //$NON-NLS-1$)
523614
}
524615

616+
private static void threadJoinHelper(Thread thread, long shutdownDeadlineNs) {
617+
long timeout = 100;
618+
int retryNumber = 0;
619+
for (;;) {
620+
long currentNanoTime = System.nanoTime();
621+
long tempTimeout = TimeUnit.NANOSECONDS.toMillis(shutdownDeadlineNs - currentNanoTime);
622+
if (tempTimeout <= 0) {
623+
// already reached shutdownDeadlineNs
624+
// or ignore the NANOSECONDS.excessNanos() which is less than 1ms
625+
IPC.logMessage(thread + " already reached shutdownDeadlineNs : currentNanoTime = " //$NON-NLS-1$
626+
+ currentNanoTime + ", tempTimeout = " + tempTimeout); //$NON-NLS-1$
627+
break;
628+
}
629+
if (timeout > tempTimeout) {
630+
// not wait beyond shutdownDeadlineNs
631+
timeout = tempTimeout;
632+
}
633+
IPC.logMessage(thread + ": currentNanoTime = " + currentNanoTime //$NON-NLS-1$
634+
+ ", tempTimeout = " + tempTimeout //$NON-NLS-1$
635+
+ ", timeout = " + timeout); //$NON-NLS-1$
636+
try {
637+
thread.join(timeout);
638+
} catch (InterruptedException e) {
639+
IPC.logMessage(thread + ": join() interrupted"); //$NON-NLS-1$
640+
break;
641+
}
642+
State state = thread.getState();
643+
if (state == Thread.State.TERMINATED) {
644+
// exit if thread is terminated
645+
IPC.logMessage(thread + " is terminated, exit"); //$NON-NLS-1$
646+
break;
647+
}
648+
IPC.logMessage(thread + ": state = " + state //$NON-NLS-1$
649+
+ ", timeout waiting for termination. Retry #" //$NON-NLS-1$
650+
+ retryNumber + ", timeout = " + timeout); //$NON-NLS-1$
651+
timeout *= 2;
652+
retryNumber += 1;
653+
if (thread == currentAttachThread) {
654+
IPC.logMessage(thread + ": currentAttachThread requires AttachHandler.terminateWaitLoop()"); //$NON-NLS-1$
655+
AttachHandler.terminateWaitLoop(true, retryNumber);
656+
} else if (thread == fileAccessTimeUpdaterThread) {
657+
IPC.logMessage(thread + ": fileAccessTimeUpdaterThread requires thread.interrupt()"); //$NON-NLS-1$
658+
thread.interrupt();
659+
} else {
660+
throw new InternalError(thread + ": unexpected"); //$NON-NLS-1$
661+
}
662+
}
663+
}
664+
525665
@Override
526666
public void run() {
527667
/*[PR CMVC 188652] Suppress OOM messages from attach API*/
@@ -534,7 +674,11 @@ public void run() {
534674
if (null == mainHandler) {
535675
return; /* the constructor failed */
536676
}
537-
long shutdownDeadlineNs = System.nanoTime() + shutdownTimeoutMs*1000000;
677+
long currentNanoTime = System.nanoTime();
678+
long shutdownDeadlineNs = currentNanoTime + TimeUnit.MILLISECONDS.toNanos(shutdownTimeoutMs);
679+
IPC.logMessage("currentNanoTime = " + currentNanoTime //$NON-NLS-1$
680+
+ ", shutdownTimeoutMs = " + shutdownTimeoutMs //$NON-NLS-1$
681+
+ ", shutdownDeadlineNs = " + shutdownDeadlineNs); //$NON-NLS-1$
538682
boolean destroySemaphore = mainHandler.terminate(true);
539683
try {
540684
/*[PR CMVC 172177] Ensure the initializer thread has terminated */
@@ -548,18 +692,9 @@ public void run() {
548692
* currentAttachThread is the same as mainHandler before the wait loop launches.
549693
* In that case, the join is redundant but harmless.
550694
*/
551-
int timeout = 100;
552-
int retryNumber = 0;
553-
while (System.nanoTime() < shutdownDeadlineNs) {
554-
currentAttachThread.join(timeout); /* timeout in milliseconds */
555-
if (currentAttachThread.getState() != Thread.State.TERMINATED) {
556-
IPC.logMessage(currentAttachThread + "Timeout waiting for wait loop termination. Retry #" + retryNumber); //$NON-NLS-1$
557-
timeout *= 2;
558-
AttachHandler.terminateWaitLoop(true, retryNumber);
559-
++retryNumber;
560-
} else {
561-
break;
562-
}
695+
threadJoinHelper(currentAttachThread, shutdownDeadlineNs);
696+
if ((fileAccessTimeUpdaterThread != null) && fileAccessTimeUpdaterThread.isAlive()) {
697+
threadJoinHelper(fileAccessTimeUpdaterThread, shutdownDeadlineNs);
563698
}
564699
} catch (InterruptedException e) {
565700
IPC.logMessage("teardown join with attach handler interrupted"); //$NON-NLS-1$

jcl/src/java.base/share/classes/openj9/internal/tools/attach/target/CommonDirectory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636
*
3737
*/
3838
public abstract class CommonDirectory {
39-
private static final String ATTACH_LOCK = "_attachlock"; //$NON-NLS-1$
39+
static final String ATTACH_LOCK = "_attachlock"; //$NON-NLS-1$
4040
private static final String COM_IBM_TOOLS_ATTACH_DIRECTORY = "com.ibm.tools.attach.directory"; //$NON-NLS-1$
4141
private static final int COMMON_DIRECTORY_PERMISSIONS = 01777; /* allow anyone to create directories, but only owner can delete */
4242
private static final int COMMON_LOCK_FILE_PERMISSIONS = 0666; /* allow anyone to create and use the file */
43-
private static final String CONTROLLER_LOCKFILE = "_controller"; //$NON-NLS-1$
43+
static final String CONTROLLER_LOCKFILE = "_controller"; //$NON-NLS-1$
4444
static final String CONTROLLER_NOTIFIER = "_notifier"; //$NON-NLS-1$
4545
static final int SEMAPHORE_OKAY = 0;
4646
private static final String TRASH_PREFIX = ".trash_"; //$NON-NLS-1$

jcl/src/java.base/share/classes/openj9/internal/tools/attach/target/IPC.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,14 @@ public class IPC {
7878
public static final String PROPERTY_DIAGNOSTICS_ERROR = OPENJ9_DIAGNOSTICS_PREFIX + "error"; //$NON-NLS-1$
7979
public static final String PROPERTY_DIAGNOSTICS_ERRORTYPE = OPENJ9_DIAGNOSTICS_PREFIX + "errortype"; //$NON-NLS-1$
8080
public static final String PROPERTY_DIAGNOSTICS_ERRORMSG = OPENJ9_DIAGNOSTICS_PREFIX + "errormsg"; //$NON-NLS-1$
81+
/**
82+
* True if operating system is Linux.
83+
*/
84+
public static final boolean isLinux;
8185
/**
8286
* True if operating system is Windows.
8387
*/
8488
public static final boolean isWindows;
85-
8689
/**
8790
* True if operating system is z/OS.
8891
*/
@@ -101,22 +104,26 @@ public class IPC {
101104
String osName = props.getProperty("os.name"); //$NON-NLS-1$
102105
boolean tempIsZos = false;
103106
boolean tempIsWindows = false;
107+
boolean tempIsLinux = false;
104108
if (null != osName) {
105109
if (osName.equalsIgnoreCase("z/OS")) { //$NON-NLS-1$
106110
tempIsZos = true;
107111
} else if (osName.startsWith("Windows")) { //$NON-NLS-1$
108112
tempIsWindows = true;
113+
} else if (osName.startsWith("Linux")) { //$NON-NLS-1$
114+
tempIsLinux = true;
109115
}
110116
}
111117
isZOS = tempIsZos;
112118
isWindows = tempIsWindows;
119+
isLinux = tempIsLinux;
113120

114121
String propUseFileLockWatchdog = props.getProperty(COM_IBM_TOOLS_ATTACH_USE_FILELOCK_WATCHDOG);
115122
if (propUseFileLockWatchdog == null) {
116123
// no system property com.ibm.tools.attach.useFileLockWatchdog is specified
117124
useFileLockWatchdog = !isZOS;
118125
} else {
119-
useFileLockWatchdog = "true".equalsIgnoreCase(propUseFileLockWatchdog);
126+
useFileLockWatchdog = "true".equalsIgnoreCase(propUseFileLockWatchdog); //$NON-NLS-1$
120127
}
121128
}
122129

0 commit comments

Comments
 (0)