1 /***
2 *
3 * Copyright 2004 Hiram Chirino
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.activeio.journal;
19
20 import java.io.IOException;
21 import java.io.PrintWriter;
22 import java.io.StringWriter;
23
24 import org.activeio.Packet;
25 import org.activeio.stats.CountStatisticImpl;
26 import org.activeio.stats.IndentPrinter;
27 import org.activeio.stats.TimeStatisticImpl;
28
29 /***
30 * A Journal filter that captures performance statistics of the filtered Journal.
31 *
32 * @version $Revision: 1.1 $
33 */
34 public class JournalStatsFilter implements Journal {
35
36 private final TimeStatisticImpl writeLatency = new TimeStatisticImpl("writeLatency", "The amount of time that is spent waiting for a record to be written to the Journal");
37 private final CountStatisticImpl writeRecordsCounter = new CountStatisticImpl("writeRecordsCounter","The number of records that have been written by the Journal");
38 private final CountStatisticImpl writeBytesCounter = new CountStatisticImpl("writeBytesCounter","The number of bytes that have been written by the Journal");
39 private final TimeStatisticImpl synchedWriteLatency = new TimeStatisticImpl(writeLatency, "synchedWriteLatency", "The amount of time that is spent waiting for a synch record to be written to the Journal");
40 private final TimeStatisticImpl unsynchedWriteLatency = new TimeStatisticImpl(writeLatency, "unsynchedWriteLatency", "The amount of time that is spent waiting for a non synch record to be written to the Journal");
41 private final TimeStatisticImpl readLatency = new TimeStatisticImpl("readLatency", "The amount of time that is spent waiting for a record to be read from the Journal");
42 private final CountStatisticImpl readBytesCounter = new CountStatisticImpl("readBytesCounter","The number of bytes that have been read by the Journal");
43
44 private final Journal next;
45 private boolean detailedStats;
46
47
48 /***
49 * Creates a JournalStatsFilter that captures performance information of <code>next</next>.
50 * @param next
51 */
52 public JournalStatsFilter(Journal next) {
53 this.next = next;
54 }
55
56 /***
57 * @see org.codehaus.activemq.journal.Journal#write(byte[], boolean)
58 */
59 public RecordLocation write(Packet data, boolean sync) throws IOException {
60
61 long start = System.currentTimeMillis();
62 RecordLocation answer = next.write(data, sync);
63 long end = System.currentTimeMillis();
64
65 writeRecordsCounter.increment();
66 writeBytesCounter.add(data.remaining());
67 if( sync )
68 synchedWriteLatency.addTime(end-start);
69 else
70 unsynchedWriteLatency.addTime(end-start);
71 return answer;
72 }
73
74 /***
75 * @see org.codehaus.activemq.journal.Journal#read(org.codehaus.activemq.journal.RecordLocation)
76 */
77 public Packet read(RecordLocation location)
78 throws InvalidRecordLocationException, IOException {
79
80 long start = System.currentTimeMillis();
81 Packet answer = next.read(location);
82 long end = System.currentTimeMillis();
83
84 readBytesCounter.add(answer.remaining());
85 readLatency.addTime(end-start);
86 return answer;
87 }
88
89 /***
90 * @see org.codehaus.activemq.journal.Journal#setMark(org.codehaus.activemq.journal.RecordLocation, boolean)
91 */
92 public void setMark(RecordLocation recordLocator, boolean force)
93 throws InvalidRecordLocationException, IOException {
94 next.setMark(recordLocator, force);
95 }
96
97 /***
98 * @see org.codehaus.activemq.journal.Journal#getMark()
99 */
100 public RecordLocation getMark() {
101 return next.getMark();
102 }
103
104 /***
105 * @see org.codehaus.activemq.journal.Journal#close()
106 */
107 public void close() throws IOException {
108 next.close();
109 }
110
111 /***
112 * @see org.codehaus.activemq.journal.Journal#setJournalEventListener(org.codehaus.activemq.journal.JournalEventListener)
113 */
114 public void setJournalEventListener(JournalEventListener eventListener) {
115 next.setJournalEventListener(eventListener);
116 }
117
118 /***
119 * @see org.codehaus.activemq.journal.Journal#getNextRecordLocation(org.codehaus.activemq.journal.RecordLocation)
120 */
121 public RecordLocation getNextRecordLocation(RecordLocation lastLocation)
122 throws IOException, InvalidRecordLocationException {
123 return next.getNextRecordLocation(lastLocation);
124 }
125
126 /***
127 * Writes the gathered statistics to the <code>out</code> object.
128 *
129 * @param out
130 */
131 public void dump(IndentPrinter out) {
132 out.printIndent();
133 out.println("Journal Stats {");
134 out.incrementIndent();
135 out.printIndent();
136 out.println("Throughput : "+ getThroughputKps() +" k/s and " + getThroughputRps() +" records/s" );
137 out.printIndent();
138 out.println("Latency with force : "+ getAvgSyncedLatencyMs() +" ms" );
139 out.printIndent();
140 out.println("Latency without force: "+ getAvgUnSyncedLatencyMs() +" ms" );
141
142 out.printIndent();
143 out.println("Raw Stats {");
144 out.incrementIndent();
145
146 out.printIndent();
147 out.println(writeRecordsCounter);
148 out.printIndent();
149 out.println(writeBytesCounter);
150 out.printIndent();
151 out.println(writeLatency);
152 out.incrementIndent();
153 out.printIndent();
154 out.println(synchedWriteLatency);
155 out.printIndent();
156 out.println(unsynchedWriteLatency);
157 out.decrementIndent();
158
159 out.printIndent();
160 out.println(readBytesCounter);
161
162 out.printIndent();
163 out.println(readLatency);
164 out.decrementIndent();
165 out.printIndent();
166 out.println("}");
167
168 out.decrementIndent();
169 out.printIndent();
170 out.println("}");
171
172 }
173
174 /***
175 * Dumps the stats to a String.
176 *
177 * @see java.lang.Object#toString()
178 */
179 public String toString() {
180 if( detailedStats ) {
181 StringWriter w = new StringWriter();
182 PrintWriter pw = new PrintWriter(w);
183 dump(new IndentPrinter(pw, " "));
184 return w.getBuffer().toString();
185 } else {
186 StringWriter w = new StringWriter();
187 PrintWriter pw = new PrintWriter(w);
188 IndentPrinter out = new IndentPrinter(pw, " ");
189 out.println("Throughput : "+ getThroughputKps() +" k/s and " + getThroughputRps() +" records/s");
190 out.printIndent();
191 out.println("Latency with force : "+getAvgSyncedLatencyMs()+" ms" );
192 out.printIndent();
193 out.println("Latency without force: "+getAvgUnSyncedLatencyMs()+" ms" );
194 return w.getBuffer().toString();
195 }
196 }
197
198 /***
199 * @param detailedStats true if details stats should be displayed by <code>toString()</code> and <code>dump</code>
200 * @return
201 */
202 public JournalStatsFilter enableDetailedStats(boolean detailedStats) {
203 this.detailedStats = detailedStats;
204 return this;
205 }
206
207 /***
208 * Gets the average throughput in k/s.
209 *
210 * @return the average throughput in k/s.
211 */
212 public double getThroughputKps() {
213 long totalTime = writeBytesCounter.getLastSampleTime()-writeBytesCounter.getStartTime();
214 return (((double)writeBytesCounter.getCount()/(double)totalTime)/(double)1024)*1000;
215 }
216
217 /***
218 * Gets the average throughput in records/s.
219 *
220 * @return the average throughput in records/s.
221 */
222 public double getThroughputRps() {
223 long totalTime = writeRecordsCounter.getLastSampleTime()-writeRecordsCounter.getStartTime();
224 return (((double)writeRecordsCounter.getCount()/(double)totalTime))*1000;
225 }
226
227 /***
228 * Gets the average number of writes done per second
229 *
230 * @return the average number of writes in w/s.
231 */
232 public double getWritesPerSecond() {
233 return writeLatency.getAveragePerSecond();
234 }
235
236 /***
237 * Gets the average sync write latency in ms.
238 *
239 * @return the average sync write latency in ms.
240 */
241 public double getAvgSyncedLatencyMs() {
242 return synchedWriteLatency.getAverageTime();
243 }
244
245 /***
246 * Gets the average non sync write latency in ms.
247 *
248 * @return the average non sync write latency in ms.
249 */
250 public double getAvgUnSyncedLatencyMs() {
251 return unsynchedWriteLatency.getAverageTime();
252 }
253
254 /***
255 * Resets the stats sample.
256 */
257 public void reset() {
258 writeLatency.reset();
259 writeBytesCounter.reset();
260 writeRecordsCounter.reset();
261 synchedWriteLatency.reset();
262 unsynchedWriteLatency.reset();
263 readLatency.reset();
264 readBytesCounter.reset();
265 }
266 }