Skip to content

Commit

Permalink
[Runtime] CRaC: no need to close the files that open with write&appen…
Browse files Browse the repository at this point in the history
…d mode when do checkpointing.

Summary: Add a new option CRaCAppendOnlyLogFiles to configure the files can be ignored when do checkpointing, and create an empty file if not exist when restore.

Testing: jdk/crac/AppendOnlyFileTest.java

Reviewers: lei.yul,denghui.ddh

Issue: #867
  • Loading branch information
lingjun-cg committed Oct 11, 2024
1 parent 05bd159 commit 65a9b8a
Show file tree
Hide file tree
Showing 22 changed files with 647 additions and 6,072 deletions.
171 changes: 171 additions & 0 deletions src/hotspot/os/linux/crac_linux.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crac_linux.hpp"
#include "runtime/globals.hpp"

//the value should equal to PseudoPersistentMode.SKIP_LOG_FILES in criuengine.c
#define SKIP_LOG_FILES_MODE 0x20

PseudoPersistent::PseudoPersistent(GrowableArray<PseudoPersistentFileDesc>
*ppfd, const char *config) :
_ppfd(ppfd), _append_files(NULL), _append_file_configs(NULL) {
if (config == NULL) {
return;
}

_append_file_configs = new(ResourceObj::C_HEAP, mtInternal) GrowableArray<AppendFileConfig *>(1, true);
if (!strcmp(config, "*")) {
AppendFileConfig *cfg = new AppendFileConfig(all, NULL, NULL);
_append_file_configs->append(cfg);
return;
}

const char *p = config, *s = config;
while (*p) {
if (*(p + 1) == ',' || *(p + 1) == '\0') {
if (p - s > 2 && *s == '*' && *(s + 1) == '.') {
_append_file_configs->append(new AppendFileConfig(by_extension, s + 2, p + 1));
} else {
_append_file_configs->append(new AppendFileConfig(by_full_path, s, p + 1));
}
if (*(p + 1) == ',') {
p += 2;
s = p;
} else {
break;
}
} else {
p++;
}
}
}


bool PseudoPersistent::write_marked(const char* image_dir) {
char *path;
if (-1 == asprintf(&path, "%s/pseudopersistent", image_dir)) {
return false;
}
FILE *f = fopen(path, "w");
if (f == NULL) {
fprintf(stderr, "open file: %s for write failed, error: %s\n",
path, strerror(errno));
free(path);
return false;
}

if (_ppfd) {
for(int i = 0 ; i < _ppfd->length();i++) {
PseudoPersistentFileDesc *ppfd = _ppfd->adr_at(i);
if (ppfd->_mark) {
fprintf(f, "%d,%s\n", ppfd->_mode, ppfd->_path);
}
}
}

if (_append_files) {
for (int i = 0; i < _append_files->length(); i++) {
fprintf(f, "%d,%s\n", SKIP_LOG_FILES_MODE, _append_files->at(i));
}
}

fclose(f);
free(path);
return true;
}

bool PseudoPersistent::in_registered_list(const char *path) {
if (!_ppfd) {
return false;
}
int j = 0;
while (j < _ppfd->length()) {
PseudoPersistentFileDesc *ppfd = _ppfd->adr_at(j);
int r = strcmp(ppfd->_path, path);
if (r == 0) {
ppfd->_mark = true;
return true;
} else if (r > 0) {
return false;
}
++j;
}
return false;
}

bool PseudoPersistent::in_configured_list(const char* path, int fd) {
if (_append_file_configs == NULL) {
return false;
}

int ret = fcntl(fd, F_GETFL);
if (ret != -1 && ((ret & O_ACCMODE) == O_WRONLY) && (ret & O_APPEND)) {
for (int i = 0; i < _append_file_configs->length(); i++) {
if (_append_file_configs->at(i)->match(path)) {
if (_append_files == NULL) {
_append_files = new(ResourceObj::C_HEAP, mtInternal) GrowableArray<char *>(2, true);
}
char *copy_path = NEW_C_HEAP_ARRAY(char, strlen(path) + 1, mtInternal);
strcpy(copy_path, path);
_append_files->append(copy_path);
return true;
}
}
}
return false;
}

bool PseudoPersistent::AppendFileConfig::match(const char *file) {
if (_type == all) {
return true;
} else if (_type == by_extension) {
const char *p = strrchr(file, '.');
return p != NULL && strlen(p + 1) == _size && !strncmp(p + 1, _start_ext_or_file, _size);
} else if (_type == by_full_path) {
return strlen(file) == _size && !strncmp(file, _start_ext_or_file, _size);
}
return false;
}

PseudoPersistent::~PseudoPersistent() {
if (_append_files != NULL) {
for (int i = 0; i < _append_files->length(); i++) {
FREE_C_HEAP_ARRAY(char, _append_files->at(i));
}
delete _append_files;
_append_files = NULL;
}

if (_append_file_configs != NULL) {
for (int i = 0; i < _append_file_configs->length(); i++) {
delete _append_file_configs->at(i);
}
delete _append_file_configs;
_append_file_configs = NULL;
}
}
84 changes: 84 additions & 0 deletions src/hotspot/os/linux/crac_linux.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

#ifndef OS_LINUX_CRAC_LINUX_HPP
#define OS_LINUX_CRAC_LINUX_HPP
#include "utilities/growableArray.hpp"

struct PseudoPersistentFileDesc {
int _mode;
bool _mark;
const char* _path;
PseudoPersistentFileDesc(int mode, const char *path) :
_mode(mode),
_path(path),
_mark(false)
{}

PseudoPersistentFileDesc():
_mode(0),
_path(NULL),
_mark(false)
{}
};

class PseudoPersistent {
private:
enum AppendFileConfigType {
all,
by_extension,
by_full_path
};

class AppendFileConfig : public CHeapObj<mtInternal> {
AppendFileConfigType _type;
size_t _size;
const char *_start_ext_or_file;
public:
AppendFileConfig(AppendFileConfigType type, const char *start_ext_or_file, const char *end_ext_or_file)
: _type(type), _start_ext_or_file(start_ext_or_file), _size(0) {
if (start_ext_or_file && end_ext_or_file) {
_size = end_ext_or_file - start_ext_or_file;
}
}
bool match(const char *file);
};

private:
GrowableArray<PseudoPersistentFileDesc> *_ppfd;
GrowableArray<char *> *_append_files;
GrowableArray<AppendFileConfig *> *_append_file_configs;
public:
PseudoPersistent(GrowableArray<PseudoPersistentFileDesc>* ppfd, const char* config);
~PseudoPersistent();

bool test_and_mark(const char *path, int fd) {
return in_registered_list(path) || in_configured_list(path, fd);
}

bool write_marked(const char* image_dir);
private:
bool in_configured_list(const char* path, int fd);
bool in_registered_list(const char *path);
};

#endif //OS_LINUX_CRAC_LINUX_HPP
86 changes: 4 additions & 82 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
#include "crac_linux.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
Expand Down Expand Up @@ -270,80 +271,6 @@ struct PersistentResourceDesc {
{}
};

struct PseudoPersistentFileDesc {
int _mode;
bool _mark;
const char* _path;
PseudoPersistentFileDesc(int mode, const char *path) :
_mode(mode),
_path(path),
_mark(false)
{}

PseudoPersistentFileDesc():
_mode(0),
_path(NULL),
_mark(false)
{}
};

class PseudoPersistent {
private:
GrowableArray<PseudoPersistentFileDesc>* _ppfd;
public:
PseudoPersistent(GrowableArray<PseudoPersistentFileDesc>* ppfd):
_ppfd(ppfd)
{}

bool test_and_mark(const char *path) {
if (!_ppfd) {
return false;
}
int j = 0;
while (j < _ppfd->length()) {
PseudoPersistentFileDesc *ppfd = _ppfd->adr_at(j);
int r = strcmp(ppfd->_path, path);
if (r == 0) {
ppfd->_mark = true;
return true;
break;
} else if (r > 0) {
return false;
break;
}
++j;
}
return false;
}

bool write_marked(const char *image_dir) {
if (!_ppfd) {
return true;
}
char *path;
if (-1 == asprintf(&path, "%s/pseudopersistent", image_dir)) {
return false;
}
FILE *f = fopen(path, "w");
if (f == NULL) {
fprintf(stderr, "open file: %s for write failed, error: %s\n",
path, strerror(errno));
free(path);
return false;
}
int j = 0;
while (j < _ppfd->length()) {
PseudoPersistentFileDesc *ppfd = _ppfd->adr_at(j);
if (ppfd->_mark) {
fprintf(f, "%d,%s\n", ppfd->_mode, ppfd->_path);
}
++j;
}
fclose(f);
free(path);
return true;
}
};

struct CracFailDep {
int _type;
Expand Down Expand Up @@ -7009,11 +6936,6 @@ int os::compare_file_modified_times(const char* file1, const char* file2) {
return diff;
}

void os::wake_up(Thread *thread) {
pthread_t tid = thread->osthread()->pthread_id();
pthread_kill(tid, SIG_WAKE_UP);
}

// CRaC

jlong os::Linux::restore_start_time() {
Expand Down Expand Up @@ -7502,7 +7424,7 @@ void VM_Crac::doit() {
do_classpaths(mark_all_in, &fds, Arguments::get_ext_dirs());
mark_persistent(&fds);

PseudoPersistent pp(_pseudo_persistent);
PseudoPersistent pp(_pseudo_persistent, CRaCAppendOnlyLogFiles);
int markcnt = 0;

// dry-run fails checkpoint
Expand All @@ -7518,8 +7440,9 @@ void VM_Crac::doit() {
const char* details = 0 < linkret ? detailsbuf : "";
print_resources("JVM: FD fd=%d type=%s: details1=\"%s\" ",
i, stat2strtype(fds.get_stat(i)->st_mode), details);
struct stat* st = fds.get_stat(i);

if (pp.test_and_mark(detailsbuf)) {
if (S_ISREG(st->st_mode) && pp.test_and_mark(detailsbuf, i)) {
markcnt++;
print_resources("OK: user registered pseudo persistent file \n");
continue;
Expand All @@ -7530,7 +7453,6 @@ void VM_Crac::doit() {
continue;
}

struct stat* st = fds.get_stat(i);
if (S_ISCHR(st->st_mode)) {
const int mjr = major(st->st_rdev);
const int mnr = minor(st->st_rdev);
Expand Down
Loading

0 comments on commit 65a9b8a

Please sign in to comment.