File Coverage

bson/bson-context.c
Criterion Covered Total %
statement 0 103 0.0
branch 0 28 0.0
condition n/a
subroutine n/a
pod n/a
total 0 131 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright 2013 MongoDB, Inc.
3             *
4             * Licensed under the Apache License, Version 2.0 (the "License");
5             * you may not use this file except in compliance with the License.
6             * You may obtain a copy of the License at
7             *
8             * http://www.apache.org/licenses/LICENSE-2.0
9             *
10             * Unless required by applicable law or agreed to in writing, software
11             * distributed under the License is distributed on an "AS IS" BASIS,
12             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13             * See the License for the specific language governing permissions and
14             * limitations under the License.
15             */
16              
17             #include "bson-compat.h"
18              
19             #include
20             #include
21             #include
22             #include
23             #include
24              
25             #if defined(__linux__)
26             #include
27             #endif
28              
29             #include "bson-atomic.h"
30             #include "bson-clock.h"
31             #include "bson-context.h"
32             #include "bson-context-private.h"
33             #include "bson-md5.h"
34             #include "bson-memory.h"
35             #include "bson-thread-private.h"
36              
37              
38             #ifndef HOST_NAME_MAX
39             #define HOST_NAME_MAX 256
40             #endif
41              
42              
43             /*
44             * Globals.
45             */
46             static bson_context_t gContextDefault;
47              
48              
49             #if defined(__linux__)
50             static uint16_t
51 0           local_gettid (void)
52             {
53 0           return syscall (SYS_gettid);
54             }
55             #endif
56              
57              
58             /*
59             *--------------------------------------------------------------------------
60             *
61             * _bson_context_get_oid_host --
62             *
63             * Retrieves the first three bytes of MD5(hostname) and assigns them
64             * to the host portion of oid.
65             *
66             * Returns:
67             * None.
68             *
69             * Side effects:
70             * @oid is modified.
71             *
72             *--------------------------------------------------------------------------
73             */
74              
75             static void
76 0           _bson_context_get_oid_host (bson_context_t *context, /* IN */
77             bson_oid_t *oid) /* OUT */
78             {
79 0           uint8_t *bytes = (uint8_t *)oid;
80             uint8_t digest[16];
81             bson_md5_t md5;
82             char hostname[HOST_NAME_MAX];
83              
84 0 0         BSON_ASSERT (context);
85 0 0         BSON_ASSERT (oid);
86              
87 0           gethostname (hostname, sizeof hostname);
88 0           hostname[HOST_NAME_MAX - 1] = '\0';
89              
90 0           bson_md5_init (&md5);
91 0           bson_md5_append (&md5, (const uint8_t *)hostname, (uint32_t)strlen (hostname));
92 0           bson_md5_finish (&md5, &digest[0]);
93              
94 0           bytes[4] = digest[0];
95 0           bytes[5] = digest[1];
96 0           bytes[6] = digest[2];
97 0           }
98              
99              
100             /*
101             *--------------------------------------------------------------------------
102             *
103             * _bson_context_get_oid_host_cached --
104             *
105             * Fetch the cached copy of the MD5(hostname).
106             *
107             * Returns:
108             * None.
109             *
110             * Side effects:
111             * @oid is modified.
112             *
113             *--------------------------------------------------------------------------
114             */
115              
116             static void
117 0           _bson_context_get_oid_host_cached (bson_context_t *context, /* IN */
118             bson_oid_t *oid) /* OUT */
119             {
120 0 0         BSON_ASSERT (context);
121 0 0         BSON_ASSERT (oid);
122              
123 0           oid->bytes[4] = context->md5[0];
124 0           oid->bytes[5] = context->md5[1];
125 0           oid->bytes[6] = context->md5[2];
126 0           }
127              
128              
129             static BSON_INLINE uint16_t
130 0           _bson_getpid (void)
131             {
132             uint16_t pid;
133             #ifdef BSON_OS_WIN32
134             DWORD real_pid;
135              
136             real_pid = GetCurrentProcessId ();
137             pid = (real_pid & 0xFFFF) ^ ((real_pid >> 16) & 0xFFFF);
138             #else
139 0           pid = getpid ();
140             #endif
141              
142 0           return pid;
143             }
144              
145              
146             /*
147             *--------------------------------------------------------------------------
148             *
149             * _bson_context_get_oid_pid --
150             *
151             * Initialize the pid field of @oid.
152             *
153             * The pid field is 2 bytes, big-endian for memcmp().
154             *
155             * Returns:
156             * None.
157             *
158             * Side effects:
159             * @oid is modified.
160             *
161             *--------------------------------------------------------------------------
162             */
163              
164             static void
165 0           _bson_context_get_oid_pid (bson_context_t *context, /* IN */
166             bson_oid_t *oid) /* OUT */
167             {
168 0           uint16_t pid = _bson_getpid ();
169 0           uint8_t *bytes = (uint8_t *)&pid;
170              
171 0 0         BSON_ASSERT (context);
172 0 0         BSON_ASSERT (oid);
173              
174 0           pid = BSON_UINT16_TO_BE (pid);
175              
176 0           oid->bytes[7] = bytes[0];
177 0           oid->bytes[8] = bytes[1];
178 0           }
179              
180              
181             /*
182             *--------------------------------------------------------------------------
183             *
184             * _bson_context_get_oid_pid_cached --
185             *
186             * Fetch the cached copy of the current pid.
187             * This helps avoid multiple calls to getpid() which is slower
188             * on some systems.
189             *
190             * Returns:
191             * None.
192             *
193             * Side effects:
194             * @oid is modified.
195             *
196             *--------------------------------------------------------------------------
197             */
198              
199             static void
200 0           _bson_context_get_oid_pid_cached (bson_context_t *context, /* IN */
201             bson_oid_t *oid) /* OUT */
202             {
203 0           oid->bytes[7] = context->pidbe[0];
204 0           oid->bytes[8] = context->pidbe[1];
205 0           }
206              
207              
208             /*
209             *--------------------------------------------------------------------------
210             *
211             * _bson_context_get_oid_seq32 --
212             *
213             * 32-bit sequence generator, non-thread-safe version.
214             *
215             * Returns:
216             * None.
217             *
218             * Side effects:
219             * @oid is modified.
220             *
221             *--------------------------------------------------------------------------
222             */
223              
224             static void
225 0           _bson_context_get_oid_seq32 (bson_context_t *context, /* IN */
226             bson_oid_t *oid) /* OUT */
227             {
228 0           uint32_t seq = context->seq32++;
229              
230 0           seq = BSON_UINT32_TO_BE (seq);
231 0           memcpy (&oid->bytes[9], ((uint8_t *)&seq) + 1, 3);
232 0           }
233              
234              
235             /*
236             *--------------------------------------------------------------------------
237             *
238             * _bson_context_get_oid_seq32_threadsafe --
239             *
240             * Thread-safe version of 32-bit sequence generator.
241             *
242             * Returns:
243             * None.
244             *
245             * Side effects:
246             * @oid is modified.
247             *
248             *--------------------------------------------------------------------------
249             */
250              
251             static void
252 0           _bson_context_get_oid_seq32_threadsafe (bson_context_t *context, /* IN */
253             bson_oid_t *oid) /* OUT */
254             {
255 0           int32_t seq = bson_atomic_int_add (&context->seq32, 1);
256              
257 0           seq = BSON_UINT32_TO_BE (seq);
258 0           memcpy (&oid->bytes[9], ((uint8_t *)&seq) + 1, 3);
259 0           }
260              
261              
262             /*
263             *--------------------------------------------------------------------------
264             *
265             * _bson_context_get_oid_seq64 --
266             *
267             * 64-bit oid sequence generator, non-thread-safe version.
268             *
269             * Returns:
270             * None.
271             *
272             * Side effects:
273             * @oid is modified.
274             *
275             *--------------------------------------------------------------------------
276             */
277              
278             static void
279 0           _bson_context_get_oid_seq64 (bson_context_t *context, /* IN */
280             bson_oid_t *oid) /* OUT */
281             {
282             uint64_t seq;
283              
284 0 0         BSON_ASSERT (context);
285 0 0         BSON_ASSERT (oid);
286              
287 0           seq = BSON_UINT64_TO_BE (context->seq64++);
288 0           memcpy (&oid->bytes[4], &seq, sizeof (seq));
289 0           }
290              
291              
292             /*
293             *--------------------------------------------------------------------------
294             *
295             * _bson_context_get_oid_seq64_threadsafe --
296             *
297             * Thread-safe 64-bit sequence generator.
298             *
299             * Returns:
300             * None.
301             *
302             * Side effects:
303             * @oid is modified.
304             *
305             *--------------------------------------------------------------------------
306             */
307              
308             static void
309 0           _bson_context_get_oid_seq64_threadsafe (bson_context_t *context, /* IN */
310             bson_oid_t *oid) /* OUT */
311             {
312 0           int64_t seq = bson_atomic_int64_add (&context->seq64, 1);
313              
314 0           seq = BSON_UINT64_TO_BE (seq);
315 0           memcpy (&oid->bytes[4], &seq, sizeof (seq));
316 0           }
317              
318              
319             static void
320 0           _bson_context_init (bson_context_t *context, /* IN */
321             bson_context_flags_t flags) /* IN */
322             {
323             struct timeval tv;
324             uint16_t pid;
325             unsigned int seed[3];
326             unsigned int real_seed;
327             bson_oid_t oid;
328              
329 0           context->flags = flags;
330 0           context->oid_get_host = _bson_context_get_oid_host_cached;
331 0           context->oid_get_pid = _bson_context_get_oid_pid_cached;
332 0           context->oid_get_seq32 = _bson_context_get_oid_seq32;
333 0           context->oid_get_seq64 = _bson_context_get_oid_seq64;
334              
335             /*
336             * Generate a seed for our the random starting position of our increment
337             * bytes. We mask off the last nibble so that the last digit of the OID will
338             * start at zero. Just to be nice.
339             *
340             * The seed itself is made up of the current time in seconds, milliseconds,
341             * and pid xored together. I welcome better solutions if at all necessary.
342             */
343 0           bson_gettimeofday (&tv);
344 0           seed[0] = (unsigned int)tv.tv_sec;
345 0           seed[1] = (unsigned int)tv.tv_usec;
346 0           seed[2] = _bson_getpid ();
347 0           real_seed = seed[0] ^ seed[1] ^ seed[2];
348              
349             #ifdef BSON_OS_WIN32
350             /* ms's runtime is multithreaded by default, so no rand_r */
351             srand(real_seed);
352             context->seq32 = rand() & 0x007FFFF0;
353             #else
354 0           context->seq32 = rand_r (&real_seed) & 0x007FFFF0;
355             #endif
356              
357 0 0         if ((flags & BSON_CONTEXT_DISABLE_HOST_CACHE)) {
358 0           context->oid_get_host = _bson_context_get_oid_host;
359             } else {
360 0           _bson_context_get_oid_host (context, &oid);
361 0           context->md5[0] = oid.bytes[4];
362 0           context->md5[1] = oid.bytes[5];
363 0           context->md5[2] = oid.bytes[6];
364             }
365              
366 0 0         if ((flags & BSON_CONTEXT_THREAD_SAFE)) {
367 0           context->oid_get_seq32 = _bson_context_get_oid_seq32_threadsafe;
368 0           context->oid_get_seq64 = _bson_context_get_oid_seq64_threadsafe;
369             }
370              
371 0 0         if ((flags & BSON_CONTEXT_DISABLE_PID_CACHE)) {
372 0           context->oid_get_pid = _bson_context_get_oid_pid;
373             } else {
374 0           pid = BSON_UINT16_TO_BE (_bson_getpid());
375             #if defined(__linux__)
376              
377 0 0         if ((flags & BSON_CONTEXT_USE_TASK_ID)) {
378             int32_t tid;
379              
380 0 0         if ((tid = local_gettid ())) {
381 0           pid = BSON_UINT16_TO_BE (tid);
382             }
383             }
384              
385             #endif
386 0           memcpy (&context->pidbe[0], &pid, 2);
387             }
388 0           }
389              
390              
391             /*
392             *--------------------------------------------------------------------------
393             *
394             * bson_context_new --
395             *
396             * Initializes a new context with the flags specified.
397             *
398             * In most cases, you want to call this with @flags set to
399             * BSON_CONTEXT_NONE.
400             *
401             * If you are running on Linux, %BSON_CONTEXT_USE_TASK_ID can result
402             * in a healthy speedup for multi-threaded scenarios.
403             *
404             * If you absolutely must have a single context for your application
405             * and use more than one thread, then %BSON_CONTEXT_THREAD_SAFE should
406             * be bitwise-or'd with your flags. This requires synchronization
407             * between threads.
408             *
409             * If you expect your hostname to change often, you may consider
410             * specifying %BSON_CONTEXT_DISABLE_HOST_CACHE so that gethostname()
411             * is called for every OID generated. This is much slower.
412             *
413             * If you expect your pid to change without notice, such as from an
414             * unexpected call to fork(), then specify
415             * %BSON_CONTEXT_DISABLE_PID_CACHE.
416             *
417             * Returns:
418             * A newly allocated bson_context_t that should be freed with
419             * bson_context_destroy().
420             *
421             * Side effects:
422             * None.
423             *
424             *--------------------------------------------------------------------------
425             */
426              
427             bson_context_t *
428 0           bson_context_new (bson_context_flags_t flags)
429             {
430             bson_context_t *context;
431              
432 0           context = bson_malloc0 (sizeof *context);
433 0           _bson_context_init (context, flags);
434              
435 0           return context;
436             }
437              
438              
439             /*
440             *--------------------------------------------------------------------------
441             *
442             * bson_context_destroy --
443             *
444             * Cleans up a bson_context_t and releases any associated resources.
445             * This should be called when you are done using @context.
446             *
447             * Returns:
448             * None.
449             *
450             * Side effects:
451             * None.
452             *
453             *--------------------------------------------------------------------------
454             */
455              
456             void
457 0           bson_context_destroy (bson_context_t *context) /* IN */
458             {
459 0 0         if (context != &gContextDefault) {
460 0           memset (context, 0, sizeof *context);
461 0           bson_free (context);
462             }
463 0           }
464              
465              
466             static
467 0           BSON_ONCE_FUN(_bson_context_init_default)
468             {
469 0           _bson_context_init (&gContextDefault,
470             (BSON_CONTEXT_THREAD_SAFE |
471             BSON_CONTEXT_DISABLE_PID_CACHE));
472 0           BSON_ONCE_RETURN;
473             }
474              
475              
476             /*
477             *--------------------------------------------------------------------------
478             *
479             * bson_context_get_default --
480             *
481             * Fetches the default, thread-safe implementation of #bson_context_t.
482             * If you need faster generation, it is recommended you create your
483             * own #bson_context_t with bson_context_new().
484             *
485             * Returns:
486             * A shared instance to the default #bson_context_t. This should not
487             * be modified or freed.
488             *
489             * Side effects:
490             * None.
491             *
492             *--------------------------------------------------------------------------
493             */
494              
495             bson_context_t *
496 0           bson_context_get_default (void)
497             {
498             static bson_once_t once = BSON_ONCE_INIT;
499              
500 0           bson_once (&once, _bson_context_init_default);
501              
502 0           return &gContextDefault;
503             }