1/*
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
27#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
28#include "jfr/writers/jfrBigEndianWriter.hpp"
29
30JfrCheckpointFlush::JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t) :
31 _result(JfrCheckpointManager::flush(old, used, requested, t)) {}
32
33JfrCheckpointWriter::JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread) :
34 JfrCheckpointWriterBase(JfrCheckpointManager::lease_buffer(thread), thread),
35 _time(JfrTicks::now()),
36 _offset(0),
37 _count(0),
38 _flushpoint(flushpoint),
39 _header(header) {
40 assert(this->is_acquired(), "invariant");
41 assert(0 == this->current_offset(), "invariant");
42 if (_header) {
43 reserve(sizeof(JfrCheckpointEntry));
44 }
45}
46
47static void write_checkpoint_header(u1* pos, int64_t size, jlong time, bool flushpoint, u4 type_count) {
48 assert(pos != NULL, "invariant");
49 JfrBigEndianWriter be_writer(pos, sizeof(JfrCheckpointEntry));
50 be_writer.write(size);
51 be_writer.write(time);
52 be_writer.write(JfrTicks::now().value() - time);
53 be_writer.write(flushpoint ? (u4)1 : (u4)0);
54 be_writer.write(type_count);
55 assert(be_writer.is_valid(), "invariant");
56}
57
58JfrCheckpointWriter::~JfrCheckpointWriter() {
59 assert(this->is_acquired(), "invariant");
60 if (!this->is_valid() || !_header) {
61 release();
62 return;
63 }
64 if (0 == count()) {
65 assert(this->used_size() == sizeof(JfrCheckpointEntry), "invariant");
66 this->seek(_offset);
67 release();
68 return;
69 }
70 assert(_header, "invariant");
71 assert(this->is_valid(), "invariant");
72 assert(count() > 0, "invariant");
73 assert(this->used_size() > sizeof(JfrCheckpointEntry), "invariant");
74 const int64_t size = this->current_offset();
75 assert(size + this->start_pos() == this->current_pos(), "invariant");
76 write_checkpoint_header(const_cast<u1*>(this->start_pos()), size, _time, is_flushpoint(), count());
77 release();
78}
79
80void JfrCheckpointWriter::set_flushpoint(bool flushpoint) {
81 _flushpoint = flushpoint;
82}
83
84bool JfrCheckpointWriter::is_flushpoint() const {
85 return _flushpoint;
86}
87
88u4 JfrCheckpointWriter::count() const {
89 return _count;
90}
91
92void JfrCheckpointWriter::set_count(u4 count) {
93 _count = count;
94}
95
96void JfrCheckpointWriter::release() {
97 assert(this->is_acquired(), "invariant");
98 if (!this->is_valid() || this->used_size() == 0) {
99 return;
100 }
101 assert(this->used_size() > 0, "invariant");
102 // write through to backing storage
103 this->commit();
104 assert(0 == this->current_offset(), "invariant");
105}
106
107void JfrCheckpointWriter::write_type(JfrTypeId type_id) {
108 assert(type_id < TYPES_END, "invariant");
109 write<u8>(type_id);
110 increment();
111}
112
113void JfrCheckpointWriter::write_key(u8 key) {
114 write(key);
115}
116
117void JfrCheckpointWriter::increment() {
118 ++_count;
119}
120
121void JfrCheckpointWriter::write_count(u4 nof_entries) {
122 write(nof_entries);
123}
124
125void JfrCheckpointWriter::write_count(u4 nof_entries, int64_t offset) {
126 write_padded_at_offset(nof_entries, offset);
127}
128
129const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointContext* ctx /* 0 */) {
130 assert(this->is_acquired(), "wrong state!");
131 if (!this->is_valid()) {
132 *size = 0;
133 return NULL;
134 }
135 if (ctx != NULL) {
136 const u1* session_start_pos = this->start_pos() + ctx->offset;
137 *size = this->current_pos() - session_start_pos;
138 return session_start_pos;
139 }
140 *size = this->used_size();
141 assert(this->start_pos() + *size == this->current_pos(), "invariant");
142 write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, is_flushpoint(), count());
143 this->seek(_offset + (_header ? sizeof(JfrCheckpointEntry) : 0));
144 set_count(0);
145 return this->start_pos();
146}
147
148const JfrCheckpointContext JfrCheckpointWriter::context() const {
149 JfrCheckpointContext ctx;
150 ctx.offset = this->current_offset();
151 ctx.count = this->count();
152 return ctx;
153}
154
155void JfrCheckpointWriter::set_context(const JfrCheckpointContext ctx) {
156 this->seek(ctx.offset);
157 set_count(ctx.count);
158}
159bool JfrCheckpointWriter::has_data() const {
160 return this->used_size() > sizeof(JfrCheckpointEntry);
161}
162
163JfrCheckpointBlobHandle JfrCheckpointWriter::checkpoint_blob() {
164 size_t size = 0;
165 const u1* data = session_data(&size);
166 return JfrCheckpointBlob::make(data, size);
167}
168
169JfrCheckpointBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) {
170 if (ctx == NULL) {
171 return checkpoint_blob();
172 }
173 size_t size = 0;
174 const u1* data = session_data(&size, ctx);
175 return JfrCheckpointBlob::make(data, size);
176}
177
178JfrCheckpointBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
179 JfrCheckpointBlobHandle data = copy(ctx);
180 if (ctx != NULL) {
181 const_cast<JfrCheckpointContext*>(ctx)->count = 0;
182 set_context(*ctx);
183 }
184 return data;
185}
186