blob: 78f749d96c4a425555c3e8a9828580662925f70f [file] [log] [blame]
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. 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.
*
* 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.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/mutex.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
static JfrRepository* _instance = NULL;
JfrRepository& JfrRepository::instance() {
return *_instance;
}
static JfrChunkWriter* _chunkwriter = NULL;
JfrChunkWriter& JfrRepository::chunkwriter() {
return *_chunkwriter;
}
JfrRepository::JfrRepository(JfrPostBox& post_box) : _path(NULL), _post_box(post_box) {}
bool JfrRepository::initialize() {
assert(_chunkwriter == NULL, "invariant");
_chunkwriter = new JfrChunkWriter();
return _chunkwriter != NULL;
}
JfrRepository::~JfrRepository() {
if (_path != NULL) {
JfrCHeapObj::free(_path, strlen(_path) + 1);
_path = NULL;
}
if (_chunkwriter != NULL) {
delete _chunkwriter;
_chunkwriter = NULL;
}
}
JfrRepository* JfrRepository::create(JfrPostBox& post_box) {
assert(_instance == NULL, "invariant");
_instance = new JfrRepository(post_box);
return _instance;
}
void JfrRepository::destroy() {
assert(_instance != NULL, "invariant");
delete _instance;
_instance = NULL;
}
void JfrRepository::on_vm_error() {
if (_path == NULL) {
// completed already
return;
}
JfrEmergencyDump::on_vm_error(_path);
}
bool JfrRepository::set_path(const char* path) {
assert(path != NULL, "trying to set the repository path with a NULL string!");
if (_path != NULL) {
// delete existing
JfrCHeapObj::free(_path, strlen(_path) + 1);
}
const size_t path_len = strlen(path);
_path = JfrCHeapObj::new_array<char>(path_len + 1);
if (_path == NULL) {
return false;
}
strncpy(_path, path, path_len + 1);
return true;
}
void JfrRepository::notify_on_new_chunk_path() {
if (Jfr::is_recording()) {
// rotations are synchronous, block until rotation completes
instance()._post_box.post(MSG_ROTATE);
}
}
void JfrRepository::set_chunk_path(const char* path) {
chunkwriter().set_path(path);
}
jlong JfrRepository::current_chunk_start_nanos() {
return chunkwriter().current_chunk_start_nanos();
}
/**
* Sets the file where data should be written.
*
* Recording Previous Current Action
* ==============================================
* true null null Ignore, keep recording in-memory
* true null file1 Start disk recording
* true file null Copy out metadata to disk and continue in-memory recording
* true file1 file2 Copy out metadata and start with new File (file2)
* false * null Ignore, but start recording to memory
* false * file Ignore, but start recording to disk
*/
void JfrRepository::set_chunk_path(jstring path, JavaThread* jt) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
ResourceMark rm(jt);
const char* const canonical_chunk_path = JfrJavaSupport::c_str(path, jt);
if (NULL == canonical_chunk_path && !_chunkwriter->is_valid()) {
// new output is NULL and current output is NULL
return;
}
instance().set_chunk_path(canonical_chunk_path);
notify_on_new_chunk_path();
}
void JfrRepository::set_path(jstring location, JavaThread* jt) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
ResourceMark rm(jt);
const char* const path = JfrJavaSupport::c_str(location, jt);
if (path != NULL) {
instance().set_path(path);
}
}
bool JfrRepository::open_chunk(bool vm_error /* false */) {
if (vm_error) {
ResourceMark rm;
_chunkwriter->set_path(JfrEmergencyDump::build_dump_path(_path));
}
return _chunkwriter->open();
}
size_t JfrRepository::close_chunk() {
return _chunkwriter->close();
}
void JfrRepository::flush(JavaThread* jt) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
if (!Jfr::is_recording()) {
return;
}
if (!_chunkwriter->is_valid()) {
return;
}
instance()._post_box.post(MSG_FLUSHPOINT);
}
size_t JfrRepository::flush_chunk() {
return _chunkwriter->flush_chunk(true);
}