1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2004,2008 Oracle.  All rights reserved.
5 *
6 * $Id: seq_stat.c,v 12.19 2008/04/19 15:20:28 mjc Exp $
7 */
8
9#include "db_config.h"
10#ifdef HAVE_64BIT_TYPES
11
12#include "db_int.h"
13#include "dbinc/db_page.h"
14#include "dbinc/db_am.h"
15#include "dbinc_auto/sequence_ext.h"
16
17#ifdef HAVE_STATISTICS
18static int __seq_print_all __P((DB_SEQUENCE *, u_int32_t));
19static int __seq_print_stats __P((DB_SEQUENCE *, u_int32_t));
20
21/*
22 * __seq_stat --
23 *	Get statistics from the sequence.
24 *
25 * PUBLIC: int __seq_stat __P((DB_SEQUENCE *, DB_SEQUENCE_STAT **, u_int32_t));
26 */
27int
28__seq_stat(seq, spp, flags)
29	DB_SEQUENCE *seq;
30	DB_SEQUENCE_STAT **spp;
31	u_int32_t flags;
32{
33	DB *dbp;
34	DBT data;
35	DB_SEQUENCE_STAT *sp;
36	DB_SEQ_RECORD record;
37	DB_THREAD_INFO *ip;
38	ENV *env;
39	int handle_check, ret, t_ret;
40
41	dbp = seq->seq_dbp;
42	env = dbp->env;
43
44	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->stat");
45
46	switch (flags) {
47	case DB_STAT_CLEAR:
48	case DB_STAT_ALL:
49	case 0:
50		break;
51	default:
52		return (__db_ferr(env, "DB_SEQUENCE->stat", 0));
53	}
54
55	ENV_ENTER(env, ip);
56
57	/* Check for replication block. */
58	handle_check = IS_ENV_REPLICATED(env);
59	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
60		handle_check = 0;
61		goto err;
62	}
63
64	/* Allocate and clear the structure. */
65	if ((ret = __os_umalloc(env, sizeof(*sp), &sp)) != 0)
66		goto err;
67	memset(sp, 0, sizeof(*sp));
68
69	if (seq->mtx_seq != MUTEX_INVALID) {
70		__mutex_set_wait_info(
71		    env, seq->mtx_seq, &sp->st_wait, &sp->st_nowait);
72
73		if (LF_ISSET(DB_STAT_CLEAR))
74			__mutex_clear(env, seq->mtx_seq);
75	}
76	memset(&data, 0, sizeof(data));
77	data.data = &record;
78	data.ulen = sizeof(record);
79	data.flags = DB_DBT_USERMEM;
80retry:	if ((ret = __db_get(dbp, ip, NULL, &seq->seq_key, &data, 0)) != 0) {
81		if (ret == DB_BUFFER_SMALL &&
82		    data.size > sizeof(seq->seq_record)) {
83			if ((ret = __os_malloc(env,
84			    data.size, &data.data)) != 0)
85				goto err;
86			data.ulen = data.size;
87			goto retry;
88		}
89		goto err;
90	}
91
92	if (data.data != &record)
93		memcpy(&record, data.data, sizeof(record));
94	sp->st_current = record.seq_value;
95	sp->st_value = seq->seq_record.seq_value;
96	sp->st_last_value = seq->seq_last_value;
97	sp->st_min = seq->seq_record.seq_min;
98	sp->st_max = seq->seq_record.seq_max;
99	sp->st_cache_size = seq->seq_cache_size;
100	sp->st_flags = seq->seq_record.flags;
101
102	*spp = sp;
103	if (data.data != &record)
104		__os_free(env, data.data);
105
106	/* Release replication block. */
107err:	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
108		ret = t_ret;
109	ENV_LEAVE(env, ip);
110	return (ret);
111}
112
113/*
114 * __seq_stat_print --
115 *	Print statistics from the sequence.
116 *
117 * PUBLIC: int __seq_stat_print __P((DB_SEQUENCE *, u_int32_t));
118 */
119int
120__seq_stat_print(seq, flags)
121	DB_SEQUENCE *seq;
122	u_int32_t flags;
123{
124	DB *dbp;
125	DB_THREAD_INFO *ip;
126	ENV *env;
127	int handle_check, ret, t_ret;
128
129	dbp = seq->seq_dbp;
130	env = dbp->env;
131
132	SEQ_ILLEGAL_BEFORE_OPEN(seq, "DB_SEQUENCE->stat_print");
133
134	ENV_ENTER(env, ip);
135
136	/* Check for replication block. */
137	handle_check = IS_ENV_REPLICATED(env);
138	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
139		handle_check = 0;
140		goto err;
141	}
142
143	if ((ret = __seq_print_stats(seq, flags)) != 0)
144		goto err;
145
146	if (LF_ISSET(DB_STAT_ALL) &&
147	    (ret = __seq_print_all(seq, flags)) != 0)
148		goto err;
149
150	/* Release replication block. */
151err:	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
152		ret = t_ret;
153
154	ENV_LEAVE(env, ip);
155	return (ret);
156
157}
158
159static const FN __db_seq_flags_fn[] = {
160	{ DB_SEQ_DEC,		"decrement" },
161	{ DB_SEQ_INC,		"increment" },
162	{ DB_SEQ_RANGE_SET,	"range set (internal)" },
163	{ DB_SEQ_WRAP,		"wraparound at end" },
164	{ 0,			NULL }
165};
166
167/*
168 * __db_get_seq_flags_fn --
169 *	Return the __db_seq_flags_fn array.
170 *
171 * PUBLIC: const FN * __db_get_seq_flags_fn __P((void));
172 */
173const FN *
174__db_get_seq_flags_fn()
175{
176	return (__db_seq_flags_fn);
177}
178
179/*
180 * __seq_print_stats --
181 *	Display sequence stat structure.
182 */
183static int
184__seq_print_stats(seq, flags)
185	DB_SEQUENCE *seq;
186	u_int32_t flags;
187{
188	DB_SEQUENCE_STAT *sp;
189	ENV *env;
190	int ret;
191
192	env = seq->seq_dbp->env;
193
194	if ((ret = __seq_stat(seq, &sp, flags)) != 0)
195		return (ret);
196	__db_dl_pct(env,
197	    "The number of sequence locks that required waiting",
198	    (u_long)sp->st_wait,
199	     DB_PCT(sp->st_wait, sp->st_wait + sp->st_nowait), NULL);
200	STAT_FMT("The current sequence value",
201	    INT64_FMT, int64_t, sp->st_current);
202	STAT_FMT("The cached sequence value",
203	    INT64_FMT, int64_t, sp->st_value);
204	STAT_FMT("The last cached sequence value",
205	    INT64_FMT, int64_t, sp->st_last_value);
206	STAT_FMT("The minimum sequence value",
207	    INT64_FMT, int64_t, sp->st_value);
208	STAT_FMT("The maximum sequence value",
209	    INT64_FMT, int64_t, sp->st_value);
210	STAT_ULONG("The cache size", sp->st_cache_size);
211	__db_prflags(env, NULL,
212	    sp->st_flags, __db_seq_flags_fn, NULL, "\tSequence flags");
213	__os_ufree(seq->seq_dbp->env, sp);
214	return (0);
215}
216
217/*
218 * __seq_print_all --
219 *	Display sequence debugging information - none for now.
220 *	(The name seems a bit strange, no?)
221 */
222static int
223__seq_print_all(seq, flags)
224	DB_SEQUENCE *seq;
225	u_int32_t flags;
226{
227	COMPQUIET(seq, NULL);
228	COMPQUIET(flags, 0);
229	return (0);
230}
231
232#else /* !HAVE_STATISTICS */
233
234int
235__seq_stat(seq, statp, flags)
236	DB_SEQUENCE *seq;
237	DB_SEQUENCE_STAT **statp;
238	u_int32_t flags;
239{
240	COMPQUIET(statp, NULL);
241	COMPQUIET(flags, 0);
242
243	return (__db_stat_not_built(seq->seq_dbp->env));
244}
245
246int
247__seq_stat_print(seq, flags)
248	DB_SEQUENCE *seq;
249	u_int32_t flags;
250{
251	COMPQUIET(flags, 0);
252
253	return (__db_stat_not_built(seq->seq_dbp->env));
254}
255
256/*
257 * __db_get_seq_flags_fn --
258 *	Return the __db_seq_flags_fn array.
259 *
260 * PUBLIC: const FN * __db_get_seq_flags_fn __P((void));
261 */
262const FN *
263__db_get_seq_flags_fn()
264{
265	static const FN __db_seq_flags_fn[] = {
266		{ 0,	NULL }
267	};
268
269	/*
270	 * !!!
271	 * The Tcl API uses this interface, stub it off.
272	 */
273	return (__db_seq_flags_fn);
274}
275#endif /* !HAVE_STATISTICS */
276#endif /* HAVE_64BIT_TYPES */
277