1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident	"%Z%%M%	%I%	%E% SMI"
27  */
28 package org.opensolaris.os.dtrace;
29 
30 import java.io.Serializable;
31 import java.io.*;
32 import java.beans.*;
33 
34 /**
35  * Detail about one or more records dropped by DTrace (not reported to
36  * {@link ConsumerListener#dataReceived(DataEvent e)
37  * ConsumerListener.dataReceived()}) due to inadequte buffer space.
38  * <p>
39  * Immutable.  Supports persistence using {@link java.beans.XMLEncoder}.
40  *
41  * @see ConsumerListener#dataDropped(DropEvent e)
42  *
43  * @author Tom Erickson
44  */
45 public final class Drop implements Serializable {
46     static final long serialVersionUID = 26653827678657381L;
47 
48     static {
49 	try {
50 	    BeanInfo info = Introspector.getBeanInfo(Drop.class);
51 	    PersistenceDelegate persistenceDelegate =
52 		    new DefaultPersistenceDelegate(
53 		    new String[] {"CPU", "kind", "count", "total",
54 		    "defaultMessage"})
55 	    {
56 		protected Expression
57 		instantiate(Object oldInstance, Encoder out)
58 		{
59 		    Drop drop = (Drop)oldInstance;
60 		    return new Expression(oldInstance, oldInstance.getClass(),
61 			    "new", new Object[] { drop.getCPU(),
62 			    drop.getKind().name(), drop.getCount(),
63 			    drop.getTotal(), drop.getDefaultMessage() });
64 		}
65 	    };
66 	    BeanDescriptor d = info.getBeanDescriptor();
67 	    d.setValue("persistenceDelegate", persistenceDelegate);
68 	} catch (IntrospectionException e) {
69 	    e.printStackTrace();
70 	}
71     }
72 
73     /**
74      * Indicates what kind of buffer space experienced the data drop
75      * (such as principal buffer or aggregation buffer) and possibly a
76      * reason.
77      */
78     public enum Kind {
79 	/** Drop to principal buffer */
80 	PRINCIPAL("Principal buffer"),
81 	/** Drop to aggregation buffer */
82 	AGGREGATION("Aggregation"),
83 	/** Dynamic drop */
84 	DYNAMIC("Dynamic"),
85 	/** Dynamic drop due to rinsing */
86 	DYNRINSE("Dynamic (rinse)"),
87 	/** Dynamic drop due to dirtiness */
88 	DYNDIRTY("Dynamic (dirty)"),
89 	/** Speculative drop */
90 	SPEC("Speculation"),
91 	/** Speculative drop due to business */
92 	SPECBUSY("Speculation (busy)"),
93 	/** Speculative drop due to unavailability */
94 	SPECUNAVAIL("Speculation (unavailable)"),
95 	/** Stack string table overflow */
96 	STKSTROVERFLOW("Stack string table overflow"),
97 	/** Error in ERROR probe */
98 	DBLERROR("error in ERROR probe"),
99 	/** Unrecognized value from native DTrace library */
100 	UNKNOWN("Unknown");
101 
102 	private String s;
103 
104 	private
Kind(String displayString)105 	Kind(String displayString)
106 	{
107 	    s = displayString;
108 	}
109 
110 	/**
111 	 * Overridden to get the default display value.  To
112 	 * internationalize the display value, use {@link Enum#name()}
113 	 * instead as an I18N lookup key.
114 	 */
115 	public String
toString()116 	toString()
117 	{
118 	    return s;
119 	}
120     }
121 
122     /** @serial */
123     private final int cpu;
124     /** @serial */
125     private final Kind kind;
126     /** @serial */
127     private final long count;
128     /** @serial */
129     private final long total;
130     /** @serial */
131     private final String defaultMessage;
132 
133     /**
134      * Creates a {@code Drop} instance with the given CPU, drop kind,
135      * drop counts, and default message.  Supports XML persistence.
136      *
137      * @param dropCPU cpu where drops occurred
138      * @param dropKindName name of enumeration value indicating the kind
139      * of buffer space where the drop occurred and possibly a reason
140      * @param dropCount number of drops
141      * @param totalDrops total number of drops since the source {@link
142      * Consumer} started running
143      * @param defaultDropMessage drop message provided by DTrace
144      * @throws IllegalArgumentException if there is no {@code Drop.Kind}
145      * value with the given name or if {@code dropCount} or {@code
146      * totalDrops} is negative
147      * @throws NullPointerException if the given {@code Drop.Kind} name
148      * or default message is {@code null}
149      */
150     public
Drop(int dropCPU, String dropKindName, long dropCount, long totalDrops, String defaultDropMessage)151     Drop(int dropCPU, String dropKindName, long dropCount, long totalDrops,
152 	    String defaultDropMessage)
153     {
154 	cpu = dropCPU;
155 	kind = Enum.valueOf(Kind.class, dropKindName);
156 	count = dropCount;
157 	total = totalDrops;
158 	defaultMessage = defaultDropMessage;
159 	validate();
160     }
161 
162     private final void
validate()163     validate()
164     {
165 	if (count < 0) {
166 	    throw new IllegalArgumentException("count is negative");
167 	}
168 	if (total < 0) {
169 	    throw new IllegalArgumentException("total is negative");
170 	}
171 	if (defaultMessage == null) {
172 	    throw new NullPointerException("default message is null");
173 	}
174     }
175 
176     /**
177      * Gets the CPU where the drops occurred.
178      *
179      * @return non-negative CPU ID, or a negative number if the CPU is
180      * unknown
181      */
182     public int
getCPU()183     getCPU()
184     {
185 	return cpu;
186     }
187 
188     /**
189      * Gets the kind of drop for all drops included in {@link
190      * #getCount()}.
191      *
192      * @return non-null drop kind
193      */
194     public Kind
getKind()195     getKind()
196     {
197 	return kind;
198     }
199 
200     /**
201      * Gets the number of drops reported by this {@code Drop} instance.
202      *
203      * @return non-negative drop count
204      */
205     public long
getCount()206     getCount()
207     {
208 	return count;
209     }
210 
211     /**
212      * Gets the total number of drops since the source {@link Consumer}
213      * started running.
214      *
215      * @return non-negative drop total since tracing started
216      */
217     public long
getTotal()218     getTotal()
219     {
220 	return total;
221     }
222 
223     /**
224      * Gets the message provided by DTrace.
225      *
226      * @return non-null message provided by DTrace
227      */
228     public String
getDefaultMessage()229     getDefaultMessage()
230     {
231 	return defaultMessage;
232     }
233 
234     private void
readObject(ObjectInputStream s)235     readObject(ObjectInputStream s)
236 	    throws IOException, ClassNotFoundException
237     {
238 	s.defaultReadObject();
239 	// check class invariants
240 	try {
241 	    validate();
242 	} catch (Exception e) {
243 	    InvalidObjectException x = new InvalidObjectException(
244 		    e.getMessage());
245 	    x.initCause(e);
246 	    throw x;
247 	}
248     }
249 
250     /**
251      * Gets a string representation of this drop instance, not intended
252      * for display.  The exact details of the representation are
253      * unspecified and subject to change, but the following format may
254      * be regarded as typical:
255      * <pre><code>
256      * class-name[property1 = value1, property2 = value2]
257      * </code></pre>
258      */
259     public String
toString()260     toString()
261     {
262 	StringBuilder buf = new StringBuilder();
263 	buf.append(Drop.class.getName());
264 	buf.append("[cpu = ");
265 	buf.append(cpu);
266 	buf.append(", kind = ");
267 	buf.append(kind);
268 	buf.append(", count = ");
269 	buf.append(count);
270 	buf.append(", total = ");
271 	buf.append(total);
272 	buf.append(", defaultMessage = ");
273 	buf.append(defaultMessage);
274 	buf.append(']');
275 	return buf.toString();
276     }
277 }
278