~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/************************************************************************
2
Memory primitives
3
4
(c) 1994, 1995 Innobase Oy
5
6
Created 5/11/1994 Heikki Tuuri
7
*************************************************************************/
8
9
#include "ut0mem.h"
10
11
#ifdef UNIV_NONINL
12
#include "ut0mem.ic"
13
#endif
14
15
#include "mem0mem.h"
16
#include "os0sync.h"
17
#include "os0thread.h"
18
19
/* This struct is placed first in every allocated memory block */
20
typedef struct ut_mem_block_struct ut_mem_block_t;
21
22
/* The total amount of memory currently allocated from the OS with malloc */
23
ulint	ut_total_allocated_memory	= 0;
24
25
struct ut_mem_block_struct{
26
	UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
27
			/* mem block list node */
28
	ulint	size;	/* size of allocated memory */
29
	ulint	magic_n;
30
};
31
32
#define UT_MEM_MAGIC_N	1601650166
33
34
/* List of all memory blocks allocated from the operating system
35
with malloc */
36
UT_LIST_BASE_NODE_T(ut_mem_block_t)   ut_mem_block_list;
37
38
os_fast_mutex_t ut_list_mutex;	/* this protects the list */
39
40
ibool  ut_mem_block_list_inited = FALSE;
41
42
ulint*	ut_mem_null_ptr	= NULL;
43
44
/**************************************************************************
45
Initializes the mem block list at database startup. */
46
static
47
void
48
ut_mem_block_list_init(void)
49
/*========================*/
50
{
51
	os_fast_mutex_init(&ut_list_mutex);
52
	UT_LIST_INIT(ut_mem_block_list);
53
	ut_mem_block_list_inited = TRUE;
54
}
55
56
/**************************************************************************
57
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
58
defined and set_to_zero is TRUE. */
59
60
void*
61
ut_malloc_low(
62
/*==========*/
63
				/* out, own: allocated memory */
64
	ulint	n,		/* in: number of bytes to allocate */
65
	ibool	set_to_zero,	/* in: TRUE if allocated memory should be
66
				set to zero if UNIV_SET_MEM_TO_ZERO is
67
				defined */
68
	ibool	assert_on_error)/* in: if TRUE, we crash mysqld if the
69
				memory cannot be allocated */
70
{
71
	ulint	retry_count	= 0;
72
	void*	ret;
73
74
	ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
75
76
	if (!ut_mem_block_list_inited) {
77
		ut_mem_block_list_init();
78
	}
79
retry:
80
	os_fast_mutex_lock(&ut_list_mutex);
81
82
	ret = malloc(n + sizeof(ut_mem_block_t));
83
84
	if (ret == NULL && retry_count < 60) {
85
		if (retry_count == 0) {
86
			ut_print_timestamp(stderr);
87
88
			fprintf(stderr,
89
				"  InnoDB: Error: cannot allocate"
90
				" %lu bytes of\n"
91
				"InnoDB: memory with malloc!"
92
				" Total allocated memory\n"
93
				"InnoDB: by InnoDB %lu bytes."
94
				" Operating system errno: %lu\n"
95
				"InnoDB: Check if you should"
96
				" increase the swap file or\n"
97
				"InnoDB: ulimits of your operating system.\n"
98
				"InnoDB: On FreeBSD check you"
99
				" have compiled the OS with\n"
100
				"InnoDB: a big enough maximum process size.\n"
101
				"InnoDB: Note that in most 32-bit"
102
				" computers the process\n"
103
				"InnoDB: memory space is limited"
104
				" to 2 GB or 4 GB.\n"
105
				"InnoDB: We keep retrying"
106
				" the allocation for 60 seconds...\n",
107
				(ulong) n, (ulong) ut_total_allocated_memory,
108
#ifdef __WIN__
109
				(ulong) GetLastError()
110
#else
111
				(ulong) errno
112
#endif
113
				);
114
		}
115
116
		os_fast_mutex_unlock(&ut_list_mutex);
117
118
		/* Sleep for a second and retry the allocation; maybe this is
119
		just a temporary shortage of memory */
120
121
		os_thread_sleep(1000000);
122
123
		retry_count++;
124
125
		goto retry;
126
	}
127
128
	if (ret == NULL) {
129
		/* Flush stderr to make more probable that the error
130
		message gets in the error file before we generate a seg
131
		fault */
132
133
		fflush(stderr);
134
135
		os_fast_mutex_unlock(&ut_list_mutex);
136
137
		/* Make an intentional seg fault so that we get a stack
138
		trace */
139
		/* Intentional segfault on NetWare causes an abend. Avoid this
140
		by graceful exit handling in ut_a(). */
141
#if (!defined __NETWARE__)
142
		if (assert_on_error) {
143
			ut_print_timestamp(stderr);
144
145
			fprintf(stderr,
146
				"  InnoDB: We now intentionally"
147
				" generate a seg fault so that\n"
148
				"InnoDB: on Linux we get a stack trace.\n");
149
150
			if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
151
		} else {
152
			return(NULL);
153
		}
154
#else
155
		ut_a(0);
156
#endif
157
	}
158
159
	if (set_to_zero) {
160
#ifdef UNIV_SET_MEM_TO_ZERO
161
		memset(ret, '\0', n + sizeof(ut_mem_block_t));
162
#endif
163
	}
164
165
	UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
166
167
	((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
168
	((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
169
170
	ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
171
172
	UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
173
			  ((ut_mem_block_t*)ret));
174
	os_fast_mutex_unlock(&ut_list_mutex);
175
176
	return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
177
}
178
179
/**************************************************************************
180
Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
181
defined. */
182
183
void*
184
ut_malloc(
185
/*======*/
186
			/* out, own: allocated memory */
187
	ulint	n)	/* in: number of bytes to allocate */
188
{
189
	return(ut_malloc_low(n, TRUE, TRUE));
190
}
191
192
/**************************************************************************
193
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
194
out. It cannot be used if we want to return an error message. Prints to
195
stderr a message if fails. */
196
197
ibool
198
ut_test_malloc(
199
/*===========*/
200
			/* out: TRUE if succeeded */
201
	ulint	n)	/* in: try to allocate this many bytes */
202
{
203
	void*	ret;
204
205
	ret = malloc(n);
206
207
	if (ret == NULL) {
208
		ut_print_timestamp(stderr);
209
		fprintf(stderr,
210
			"  InnoDB: Error: cannot allocate"
211
			" %lu bytes of memory for\n"
212
			"InnoDB: a BLOB with malloc! Total allocated memory\n"
213
			"InnoDB: by InnoDB %lu bytes."
214
			" Operating system errno: %d\n"
215
			"InnoDB: Check if you should increase"
216
			" the swap file or\n"
217
			"InnoDB: ulimits of your operating system.\n"
218
			"InnoDB: On FreeBSD check you have"
219
			" compiled the OS with\n"
220
			"InnoDB: a big enough maximum process size.\n",
221
			(ulong) n,
222
			(ulong) ut_total_allocated_memory,
223
			(int) errno);
224
		return(FALSE);
225
	}
226
227
	free(ret);
228
229
	return(TRUE);
230
}
231
232
/**************************************************************************
233
Frees a memory block allocated with ut_malloc. */
234
235
void
236
ut_free(
237
/*====*/
238
	void* ptr)  /* in, own: memory block */
239
{
240
	ut_mem_block_t* block;
241
242
	block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
243
244
	os_fast_mutex_lock(&ut_list_mutex);
245
246
	ut_a(block->magic_n == UT_MEM_MAGIC_N);
247
	ut_a(ut_total_allocated_memory >= block->size);
248
249
	ut_total_allocated_memory -= block->size;
250
251
	UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
252
	free(block);
253
254
	os_fast_mutex_unlock(&ut_list_mutex);
255
}
256
257
/**************************************************************************
258
Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
259
use this function because the allocation functions in mem0mem.h are the
260
recommended ones in InnoDB.
261
262
man realloc in Linux, 2004:
263
264
       realloc()  changes the size of the memory block pointed to
265
       by ptr to size bytes.  The contents will be  unchanged  to
266
       the minimum of the old and new sizes; newly allocated memĀ­
267
       ory will be uninitialized.  If ptr is NULL,  the	 call  is
268
       equivalent  to malloc(size); if size is equal to zero, the
269
       call is equivalent to free(ptr).	 Unless ptr is	NULL,  it
270
       must  have  been	 returned by an earlier call to malloc(),
271
       calloc() or realloc().
272
273
RETURN VALUE
274
       realloc() returns a pointer to the newly allocated memory,
275
       which is suitably aligned for any kind of variable and may
276
       be different from ptr, or NULL if the  request  fails.  If
277
       size  was equal to 0, either NULL or a pointer suitable to
278
       be passed to free() is returned.	 If realloc()  fails  the
279
       original	 block	is  left  untouched  - it is not freed or
280
       moved. */
281
282
void*
283
ut_realloc(
284
/*=======*/
285
			/* out, own: pointer to new mem block or NULL */
286
	void*	ptr,	/* in: pointer to old block or NULL */
287
	ulint	size)	/* in: desired size */
288
{
289
	ut_mem_block_t* block;
290
	ulint		old_size;
291
	ulint		min_size;
292
	void*		new_ptr;
293
294
	if (ptr == NULL) {
295
296
		return(ut_malloc(size));
297
	}
298
299
	if (size == 0) {
300
		ut_free(ptr);
301
302
		return(NULL);
303
	}
304
305
	block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
306
307
	ut_a(block->magic_n == UT_MEM_MAGIC_N);
308
309
	old_size = block->size - sizeof(ut_mem_block_t);
310
311
	if (size < old_size) {
312
		min_size = size;
313
	} else {
314
		min_size = old_size;
315
	}
316
317
	new_ptr = ut_malloc(size);
318
319
	if (new_ptr == NULL) {
320
321
		return(NULL);
322
	}
323
324
	/* Copy the old data from ptr */
325
	ut_memcpy(new_ptr, ptr, min_size);
326
327
	ut_free(ptr);
328
329
	return(new_ptr);
330
}
331
332
/**************************************************************************
333
Frees in shutdown all allocated memory not freed yet. */
334
335
void
336
ut_free_all_mem(void)
337
/*=================*/
338
{
339
	ut_mem_block_t* block;
340
341
	os_fast_mutex_free(&ut_list_mutex);
342
343
	while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
344
345
		ut_a(block->magic_n == UT_MEM_MAGIC_N);
346
		ut_a(ut_total_allocated_memory >= block->size);
347
348
		ut_total_allocated_memory -= block->size;
349
350
		UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
351
		free(block);
352
	}
353
354
	if (ut_total_allocated_memory != 0) {
355
		fprintf(stderr,
356
			"InnoDB: Warning: after shutdown"
357
			" total allocated memory is %lu\n",
358
			(ulong) ut_total_allocated_memory);
359
	}
360
}
361
362
/**************************************************************************
363
Copies up to size - 1 characters from the NUL-terminated string src to
364
dst, NUL-terminating the result. Returns strlen(src), so truncation
365
occurred if the return value >= size. */
366
367
ulint
368
ut_strlcpy(
369
/*=======*/
370
				/* out: strlen(src) */
371
	char*		dst,	/* in: destination buffer */
372
	const char*	src,	/* in: source buffer */
373
	ulint		size)	/* in: size of destination buffer */
374
{
375
	ulint	src_size = strlen(src);
376
377
	if (size != 0) {
378
		ulint	n = ut_min(src_size, size - 1);
379
380
		memcpy(dst, src, n);
381
		dst[n] = '\0';
382
	}
383
384
	return(src_size);
385
}
386
387
/**************************************************************************
388
Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
389
(size - 1) bytes of src, not the first. */
390
391
ulint
392
ut_strlcpy_rev(
393
/*===========*/
394
				/* out: strlen(src) */
395
	char*		dst,	/* in: destination buffer */
396
	const char*	src,	/* in: source buffer */
397
	ulint		size)	/* in: size of destination buffer */
398
{
399
	ulint	src_size = strlen(src);
400
401
	if (size != 0) {
402
		ulint	n = ut_min(src_size, size - 1);
403
404
		memcpy(dst, src + src_size - n, n + 1);
405
	}
406
407
	return(src_size);
408
}
409
410
/**************************************************************************
411
Make a quoted copy of a NUL-terminated string.	Leading and trailing
412
quotes will not be included; only embedded quotes will be escaped.
413
See also ut_strlenq() and ut_memcpyq(). */
414
415
char*
416
ut_strcpyq(
417
/*=======*/
418
				/* out: pointer to end of dest */
419
	char*		dest,	/* in: output buffer */
420
	char		q,	/* in: the quote character */
421
	const char*	src)	/* in: null-terminated string */
422
{
423
	while (*src) {
424
		if ((*dest++ = *src++) == q) {
425
			*dest++ = q;
426
		}
427
	}
428
429
	return(dest);
430
}
431
432
/**************************************************************************
433
Make a quoted copy of a fixed-length string.  Leading and trailing
434
quotes will not be included; only embedded quotes will be escaped.
435
See also ut_strlenq() and ut_strcpyq(). */
436
437
char*
438
ut_memcpyq(
439
/*=======*/
440
				/* out: pointer to end of dest */
441
	char*		dest,	/* in: output buffer */
442
	char		q,	/* in: the quote character */
443
	const char*	src,	/* in: string to be quoted */
444
	ulint		len)	/* in: length of src */
445
{
446
	const char*	srcend = src + len;
447
448
	while (src < srcend) {
449
		if ((*dest++ = *src++) == q) {
450
			*dest++ = q;
451
		}
452
	}
453
454
	return(dest);
455
}
456
457
/**************************************************************************
458
Return the number of times s2 occurs in s1. Overlapping instances of s2
459
are only counted once. */
460
461
ulint
462
ut_strcount(
463
/*========*/
464
				/* out: the number of times s2 occurs in s1 */
465
	const char*	s1,	/* in: string to search in */
466
	const char*	s2)	/* in: string to search for */
467
{
468
	ulint	count = 0;
469
	ulint	len = strlen(s2);
470
471
	if (len == 0) {
472
473
		return(0);
474
	}
475
476
	for (;;) {
477
		s1 = strstr(s1, s2);
478
479
		if (!s1) {
480
481
			break;
482
		}
483
484
		count++;
485
		s1 += len;
486
	}
487
488
	return(count);
489
}
490
491
/**************************************************************************
492
Replace every occurrence of s1 in str with s2. Overlapping instances of s1
493
are only replaced once. */
494
495
char *
496
ut_strreplace(
497
/*==========*/
498
				/* out, own: modified string, must be
499
				freed with mem_free() */
500
	const char*	str,	/* in: string to operate on */
501
	const char*	s1,	/* in: string to replace */
502
	const char*	s2)	/* in: string to replace s1 with */
503
{
504
	char*		new_str;
505
	char*		ptr;
506
	const char*	str_end;
507
	ulint		str_len = strlen(str);
508
	ulint		s1_len = strlen(s1);
509
	ulint		s2_len = strlen(s2);
510
	ulint		count = 0;
511
	int		len_delta = (int)s2_len - (int)s1_len;
512
513
	str_end = str + str_len;
514
515
	if (len_delta <= 0) {
516
		len_delta = 0;
517
	} else {
518
		count = ut_strcount(str, s1);
519
	}
520
521
	new_str = mem_alloc(str_len + count * len_delta + 1);
522
	ptr = new_str;
523
524
	while (str) {
525
		const char*	next = strstr(str, s1);
526
527
		if (!next) {
528
			next = str_end;
529
		}
530
531
		memcpy(ptr, str, next - str);
532
		ptr += next - str;
533
534
		if (next == str_end) {
535
536
			break;
537
		}
538
539
		memcpy(ptr, s2, s2_len);
540
		ptr += s2_len;
541
542
		str = next + s1_len;
543
	}
544
545
	*ptr = '\0';
546
547
	return(new_str);
548
}