Dep/MySQL: Updated MySQL sources to version 5.5.9 (current GA)
This commit is contained in:
@@ -42,7 +42,7 @@
|
||||
|
||||
my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
|
||||
void *init_buffer, uint init_alloc,
|
||||
uint alloc_increment CALLER_INFO_PROTO)
|
||||
uint alloc_increment)
|
||||
{
|
||||
DBUG_ENTER("init_dynamic_array");
|
||||
if (!alloc_increment)
|
||||
@@ -67,14 +67,13 @@ my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
|
||||
Since the dynamic array is usable even if allocation fails here malloc
|
||||
should not throw an error
|
||||
*/
|
||||
if (!(array->buffer= (uchar*) my_malloc_ci(element_size*init_alloc, MYF(0))))
|
||||
if (!(array->buffer= (uchar*) my_malloc(element_size*init_alloc, MYF(0))))
|
||||
array->max_element=0;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
|
||||
uint init_alloc,
|
||||
uint alloc_increment CALLER_INFO_PROTO)
|
||||
uint init_alloc, uint alloc_increment)
|
||||
{
|
||||
/* placeholder to preserve ABI */
|
||||
return my_init_dynamic_array_ci(array, element_size, init_alloc,
|
||||
@@ -306,7 +305,7 @@ void delete_dynamic(DYNAMIC_ARRAY *array)
|
||||
else
|
||||
if (array->buffer)
|
||||
{
|
||||
my_free(array->buffer,MYF(MY_WME));
|
||||
my_free(array->buffer);
|
||||
array->buffer=0;
|
||||
array->elements=array->max_element=0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/* Copyright (C) 2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h> /* strchr() */
|
||||
#include <m_ctype.h> /* my_isspace() */
|
||||
#include <base64.h>
|
||||
|
||||
#ifndef MAIN
|
||||
|
||||
static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
int
|
||||
base64_needed_encoded_length(int length_of_data)
|
||||
{
|
||||
int nb_base64_chars;
|
||||
nb_base64_chars= (length_of_data + 2) / 3 * 4;
|
||||
|
||||
return
|
||||
nb_base64_chars + /* base64 char incl padding */
|
||||
(nb_base64_chars - 1)/ 76 + /* newlines */
|
||||
1; /* NUL termination of string */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
base64_needed_decoded_length(int length_of_encoded_data)
|
||||
{
|
||||
return (int) ceil(length_of_encoded_data * 3 / 4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Encode a data as base64.
|
||||
|
||||
Note: We require that dst is pre-allocated to correct size.
|
||||
See base64_needed_encoded_length().
|
||||
*/
|
||||
|
||||
int
|
||||
base64_encode(const void *src, size_t src_len, char *dst)
|
||||
{
|
||||
const unsigned char *s= (const unsigned char*)src;
|
||||
size_t i= 0;
|
||||
size_t len= 0;
|
||||
|
||||
for (; i < src_len; len += 4)
|
||||
{
|
||||
unsigned c;
|
||||
|
||||
if (len == 76)
|
||||
{
|
||||
len= 0;
|
||||
*dst++= '\n';
|
||||
}
|
||||
|
||||
c= s[i++];
|
||||
c <<= 8;
|
||||
|
||||
if (i < src_len)
|
||||
c += s[i];
|
||||
c <<= 8;
|
||||
i++;
|
||||
|
||||
if (i < src_len)
|
||||
c += s[i];
|
||||
i++;
|
||||
|
||||
*dst++= base64_table[(c >> 18) & 0x3f];
|
||||
*dst++= base64_table[(c >> 12) & 0x3f];
|
||||
|
||||
if (i > (src_len + 1))
|
||||
*dst++= '=';
|
||||
else
|
||||
*dst++= base64_table[(c >> 6) & 0x3f];
|
||||
|
||||
if (i > src_len)
|
||||
*dst++= '=';
|
||||
else
|
||||
*dst++= base64_table[(c >> 0) & 0x3f];
|
||||
}
|
||||
*dst= '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline uint
|
||||
pos(unsigned char c)
|
||||
{
|
||||
return (uint) (strchr(base64_table, c) - base64_table);
|
||||
}
|
||||
|
||||
|
||||
#define SKIP_SPACE(src, i, size) \
|
||||
{ \
|
||||
while (i < size && my_isspace(&my_charset_latin1, * src)) \
|
||||
{ \
|
||||
i++; \
|
||||
src++; \
|
||||
} \
|
||||
if (i == size) \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Decode a base64 string
|
||||
|
||||
SYNOPSIS
|
||||
base64_decode()
|
||||
src Pointer to base64-encoded string
|
||||
len Length of string at 'src'
|
||||
dst Pointer to location where decoded data will be stored
|
||||
end_ptr Pointer to variable that will refer to the character
|
||||
after the end of the encoded data that were decoded. Can
|
||||
be NULL.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The base64-encoded data in the range ['src','*end_ptr') will be
|
||||
decoded and stored starting at 'dst'. The decoding will stop
|
||||
after 'len' characters have been read from 'src', or when padding
|
||||
occurs in the base64-encoded data. In either case: if 'end_ptr' is
|
||||
non-null, '*end_ptr' will be set to point to the character after
|
||||
the last read character, even in the presence of error.
|
||||
|
||||
NOTE
|
||||
We require that 'dst' is pre-allocated to correct size.
|
||||
|
||||
SEE ALSO
|
||||
base64_needed_decoded_length().
|
||||
|
||||
RETURN VALUE
|
||||
Number of bytes written at 'dst' or -1 in case of failure
|
||||
*/
|
||||
int
|
||||
base64_decode(const char *src_base, size_t len,
|
||||
void *dst, const char **end_ptr)
|
||||
{
|
||||
char b[3];
|
||||
size_t i= 0;
|
||||
char *dst_base= (char *)dst;
|
||||
char const *src= src_base;
|
||||
char *d= dst_base;
|
||||
size_t j;
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
unsigned c= 0;
|
||||
size_t mark= 0;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
c += pos(*src++);
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
c += pos(*src++);
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
if (*src != '=')
|
||||
c += pos(*src++);
|
||||
else
|
||||
{
|
||||
src += 2; /* There should be two bytes padding */
|
||||
i= len;
|
||||
mark= 2;
|
||||
c <<= 6;
|
||||
goto end;
|
||||
}
|
||||
c <<= 6;
|
||||
i++;
|
||||
|
||||
SKIP_SPACE(src, i, len);
|
||||
|
||||
if (*src != '=')
|
||||
c += pos(*src++);
|
||||
else
|
||||
{
|
||||
src += 1; /* There should be one byte padding */
|
||||
i= len;
|
||||
mark= 1;
|
||||
goto end;
|
||||
}
|
||||
i++;
|
||||
|
||||
end:
|
||||
b[0]= (c >> 16) & 0xff;
|
||||
b[1]= (c >> 8) & 0xff;
|
||||
b[2]= (c >> 0) & 0xff;
|
||||
|
||||
for (j=0; j<3-mark; j++)
|
||||
*d++= b[j];
|
||||
}
|
||||
|
||||
if (end_ptr != NULL)
|
||||
*end_ptr= src;
|
||||
|
||||
/*
|
||||
The variable 'i' is set to 'len' when padding has been read, so it
|
||||
does not actually reflect the number of bytes read from 'src'.
|
||||
*/
|
||||
return i != len ? -1 : (int) (d - dst_base);
|
||||
}
|
||||
|
||||
|
||||
#else /* MAIN */
|
||||
|
||||
#define require(b) { \
|
||||
if (!(b)) { \
|
||||
printf("Require failed at %s:%d\n", __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int i;
|
||||
size_t j;
|
||||
size_t k, l;
|
||||
size_t dst_len;
|
||||
size_t needed_length;
|
||||
|
||||
for (i= 0; i < 500; i++)
|
||||
{
|
||||
/* Create source data */
|
||||
const size_t src_len= rand() % 1000 + 1;
|
||||
|
||||
char * src= (char *) malloc(src_len);
|
||||
char * s= src;
|
||||
char * str;
|
||||
char * dst;
|
||||
|
||||
require(src);
|
||||
for (j= 0; j<src_len; j++)
|
||||
{
|
||||
char c= rand();
|
||||
*s++= c;
|
||||
}
|
||||
|
||||
/* Encode */
|
||||
needed_length= base64_needed_encoded_length(src_len);
|
||||
str= (char *) malloc(needed_length);
|
||||
require(str);
|
||||
for (k= 0; k < needed_length; k++)
|
||||
str[k]= 0xff; /* Fill memory to check correct NUL termination */
|
||||
require(base64_encode(src, src_len, str) == 0);
|
||||
require(needed_length == strlen(str) + 1);
|
||||
|
||||
/* Decode */
|
||||
dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
|
||||
require(dst);
|
||||
dst_len= base64_decode(str, strlen(str), dst, NULL);
|
||||
require(dst_len == src_len);
|
||||
|
||||
if (memcmp(src, dst, src_len) != 0)
|
||||
{
|
||||
printf(" --------- src --------- --------- dst ---------\n");
|
||||
for (k= 0; k<src_len; k+=8)
|
||||
{
|
||||
printf("%.4x ", (uint) k);
|
||||
for (l=0; l<8 && k+l<src_len; l++)
|
||||
{
|
||||
unsigned char c= src[k+l];
|
||||
printf("%.2x ", (unsigned)c);
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
|
||||
for (l=0; l<8 && k+l<dst_len; l++)
|
||||
{
|
||||
unsigned char c= dst[k+l];
|
||||
printf("%.2x ", (unsigned)c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("src length: %.8x, dst length: %.8x\n",
|
||||
(uint) src_len, (uint) dst_len);
|
||||
require(0);
|
||||
}
|
||||
}
|
||||
printf("Test succeeded.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -42,8 +42,56 @@ extern CHARSET_INFO my_charset_ucs2_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_ucs2_sinhala_uca_ci;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf32
|
||||
extern CHARSET_INFO my_charset_utf32_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf32_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf32 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf16
|
||||
extern CHARSET_INFO my_charset_utf16_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf16_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf16 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8
|
||||
extern CHARSET_INFO my_charset_utf8_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_latvian_uca_ci;
|
||||
@@ -63,11 +111,34 @@ extern CHARSET_INFO my_charset_utf8_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8_sinhala_uca_ci;
|
||||
#ifdef HAVE_UTF8_GENERAL_CS
|
||||
extern CHARSET_INFO my_charset_utf8_general_cs;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8mb4
|
||||
extern CHARSET_INFO my_charset_utf8mb4_icelandic_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_latvian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_romanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_slovenian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_polish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_estonian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_spanish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_swedish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_turkish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_czech_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_danish_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_lithuanian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_slovak_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_spanish2_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_roman_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_persian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_esperanto_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_hungarian_uca_ci;
|
||||
extern CHARSET_INFO my_charset_utf8mb4_sinhala_uca_ci;
|
||||
#endif /* HAVE_CHARSET_utf8mb4 */
|
||||
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
|
||||
my_bool init_compiled_charsets(myf flags __attribute__((unused)))
|
||||
@@ -152,6 +223,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
|
||||
add_compiled_collation(&my_charset_ucs2_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_ucs2_sinhala_uca_ci);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -186,8 +258,93 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
|
||||
add_compiled_collation(&my_charset_utf8_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8_sinhala_uca_ci);
|
||||
#endif
|
||||
#endif
|
||||
#endif /* HAVE_CHARSET_utf8 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf8mb4
|
||||
add_compiled_collation(&my_charset_utf8mb4_general_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf8mb4_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf8mb4_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
#endif /* HAVE_CHARSET_utf8mb4 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf16
|
||||
add_compiled_collation(&my_charset_utf16_general_ci);
|
||||
add_compiled_collation(&my_charset_utf16_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf16_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf16_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf16_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIOINS */
|
||||
#endif /* HAVE_CHARSET_utf16 */
|
||||
|
||||
|
||||
#ifdef HAVE_CHARSET_utf32
|
||||
add_compiled_collation(&my_charset_utf32_general_ci);
|
||||
add_compiled_collation(&my_charset_utf32_bin);
|
||||
#ifdef HAVE_UCA_COLLATIONS
|
||||
add_compiled_collation(&my_charset_utf32_unicode_ci);
|
||||
add_compiled_collation(&my_charset_utf32_icelandic_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_latvian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_romanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_slovenian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_polish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_estonian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_spanish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_swedish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_turkish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_czech_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_danish_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_lithuanian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_slovak_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_spanish2_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_roman_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_persian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_esperanto_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_hungarian_uca_ci);
|
||||
add_compiled_collation(&my_charset_utf32_sinhala_uca_ci);
|
||||
#endif /* HAVE_UCA_COLLATIONS */
|
||||
#endif /* HAVE_CHARSET_utf32 */
|
||||
|
||||
/* Copy compiled charsets */
|
||||
for (cs=compiled_charsets; cs->name; cs++)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -42,7 +42,7 @@ get_collation_number_internal(const char *name)
|
||||
{
|
||||
CHARSET_INFO **cs;
|
||||
for (cs= all_charsets;
|
||||
cs < all_charsets+array_elements(all_charsets)-1 ;
|
||||
cs < all_charsets + array_elements(all_charsets);
|
||||
cs++)
|
||||
{
|
||||
if ( cs[0] && cs[0]->name &&
|
||||
@@ -251,12 +251,38 @@ static int add_collation(CHARSET_INFO *cs)
|
||||
{
|
||||
#if defined(HAVE_CHARSET_ucs2) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_ucs2_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf8"))
|
||||
else if (!strcmp(cs->csname, "utf8") || !strcmp(cs->csname, "utf8mb3"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf8) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf8_unicode_ci);
|
||||
newcs->ctype= my_charset_utf8_unicode_ci.ctype;
|
||||
if (init_state_maps(newcs))
|
||||
return MY_XML_ERROR;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf8mb4"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf8mb4) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf8mb4_unicode_ci);
|
||||
newcs->ctype= my_charset_utf8mb4_unicode_ci.ctype;
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf16"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf16) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf16_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cs->csname, "utf32"))
|
||||
{
|
||||
#if defined (HAVE_CHARSET_utf32) && defined(HAVE_UCA_COLLATIONS)
|
||||
copy_uca_collation(newcs, &my_charset_utf32_unicode_ci);
|
||||
newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -283,6 +309,8 @@ static int add_collation(CHARSET_INFO *cs)
|
||||
|
||||
if (my_charset_is_8bit_pure_ascii(all_charsets[cs->number]))
|
||||
all_charsets[cs->number]->state|= MY_CS_PUREASCII;
|
||||
if (!my_charset_is_ascii_compatible(cs))
|
||||
all_charsets[cs->number]->state|= MY_CS_NONASCII;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -338,10 +366,10 @@ static my_bool my_read_charset_file(const char *filename, myf myflags)
|
||||
!(buf= (uchar*) my_malloc(len,myflags)))
|
||||
return TRUE;
|
||||
|
||||
if ((fd=my_open(filename,O_RDONLY,myflags)) < 0)
|
||||
if ((fd= mysql_file_open(key_file_charset, filename, O_RDONLY, myflags)) < 0)
|
||||
goto error;
|
||||
tmp_len=my_read(fd, buf, len, myflags);
|
||||
my_close(fd,myflags);
|
||||
tmp_len= mysql_file_read(fd, buf, len, myflags);
|
||||
mysql_file_close(fd, myflags);
|
||||
if (tmp_len != len)
|
||||
goto error;
|
||||
|
||||
@@ -355,11 +383,11 @@ static my_bool my_read_charset_file(const char *filename, myf myflags)
|
||||
#endif
|
||||
}
|
||||
|
||||
my_free(buf, myflags);
|
||||
my_free(buf);
|
||||
return FALSE;
|
||||
|
||||
error:
|
||||
my_free(buf, myflags);
|
||||
my_free(buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -386,7 +414,7 @@ char *get_charsets_dir(char *buf)
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
CHARSET_INFO *all_charsets[256]={NULL};
|
||||
CHARSET_INFO *all_charsets[MY_ALL_CHARSETS_SIZE]={NULL};
|
||||
CHARSET_INFO *default_charset_info = &my_charset_latin1;
|
||||
|
||||
void add_compiled_collation(CHARSET_INFO *cs)
|
||||
@@ -411,7 +439,7 @@ static void init_available_charsets(void)
|
||||
|
||||
bzero(&all_charsets,sizeof(all_charsets));
|
||||
init_compiled_charsets(MYF(0));
|
||||
|
||||
|
||||
/* Copy compiled charsets */
|
||||
for (cs=all_charsets;
|
||||
cs < all_charsets+array_elements(all_charsets)-1 ;
|
||||
@@ -424,7 +452,7 @@ static void init_available_charsets(void)
|
||||
*cs= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strmov(get_charsets_dir(fname), MY_CHARSET_INDEX);
|
||||
my_read_charset_file(fname, MYF(0));
|
||||
}
|
||||
@@ -435,20 +463,39 @@ void free_charsets(void)
|
||||
charsets_initialized= charsets_template;
|
||||
}
|
||||
|
||||
uint get_collation_number(const char *name)
|
||||
|
||||
static const char*
|
||||
get_collation_name_alias(const char *name, char *buf, size_t bufsize)
|
||||
{
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
return get_collation_number_internal(name);
|
||||
if (!strncasecmp(name, "utf8mb3_", 8))
|
||||
{
|
||||
my_snprintf(buf, bufsize, "utf8_%s", name + 8);
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint get_charset_number(const char *charset_name, uint cs_flags)
|
||||
uint get_collation_number(const char *name)
|
||||
{
|
||||
uint id;
|
||||
char alias[64];
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
if ((id= get_collation_number_internal(name)))
|
||||
return id;
|
||||
if ((name= get_collation_name_alias(name, alias, sizeof(alias))))
|
||||
return get_collation_number_internal(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint
|
||||
get_charset_number_internal(const char *charset_name, uint cs_flags)
|
||||
{
|
||||
CHARSET_INFO **cs;
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
for (cs= all_charsets;
|
||||
cs < all_charsets+array_elements(all_charsets)-1 ;
|
||||
cs < all_charsets + array_elements(all_charsets);
|
||||
cs++)
|
||||
{
|
||||
if ( cs[0] && cs[0]->csname && (cs[0]->state & cs_flags) &&
|
||||
@@ -459,6 +506,27 @@ uint get_charset_number(const char *charset_name, uint cs_flags)
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
get_charset_name_alias(const char *name)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, name, "utf8mb3"))
|
||||
return "utf8";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
uint get_charset_number(const char *charset_name, uint cs_flags)
|
||||
{
|
||||
uint id;
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
if ((id= get_charset_number_internal(charset_name, cs_flags)))
|
||||
return id;
|
||||
if ((charset_name= get_charset_name_alias(charset_name)))
|
||||
return get_charset_number_internal(charset_name, cs_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char *get_charset_name(uint charset_number)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
@@ -486,7 +554,7 @@ static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
|
||||
To make things thread safe we are not allowing other threads to interfere
|
||||
while we may changing the cs_info_table
|
||||
*/
|
||||
pthread_mutex_lock(&THR_LOCK_charset);
|
||||
mysql_mutex_lock(&THR_LOCK_charset);
|
||||
|
||||
if (!(cs->state & (MY_CS_COMPILED|MY_CS_LOADED))) /* if CS is not in memory */
|
||||
{
|
||||
@@ -508,7 +576,7 @@ static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags)
|
||||
else
|
||||
cs= NULL;
|
||||
|
||||
pthread_mutex_unlock(&THR_LOCK_charset);
|
||||
mysql_mutex_unlock(&THR_LOCK_charset);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
@@ -522,7 +590,7 @@ CHARSET_INFO *get_charset(uint cs_number, myf flags)
|
||||
|
||||
my_pthread_once(&charsets_initialized, init_available_charsets);
|
||||
|
||||
if (!cs_number || cs_number >= array_elements(all_charsets)-1)
|
||||
if (!cs_number || cs_number > array_elements(all_charsets))
|
||||
return NULL;
|
||||
|
||||
cs=get_internal_charset(cs_number, flags);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <zlib.h>
|
||||
|
||||
/*
|
||||
Calculate a long checksum for a memoryblock.
|
||||
|
||||
SYNOPSIS
|
||||
my_checksum()
|
||||
crc start value for crc
|
||||
pos pointer to memory block
|
||||
length length of the block
|
||||
*/
|
||||
|
||||
ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length)
|
||||
{
|
||||
return (ha_checksum)crc32((uint)crc, pos, (uint)length);
|
||||
}
|
||||
|
||||
+111
-41
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -41,9 +41,37 @@
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
arguments separator
|
||||
|
||||
load_defaults() loads arguments from config file and put them
|
||||
before the arguments from command line, this separator is used to
|
||||
separate the arguments loaded from config file and arguments user
|
||||
provided on command line.
|
||||
|
||||
Options with value loaded from config file are always in the form
|
||||
'--option=value', while for command line options, the value can be
|
||||
given as the next argument. Thus we used a separator so that
|
||||
handle_options() can distinguish them.
|
||||
|
||||
Note: any other places that does not need to distinguish them
|
||||
should skip the separator.
|
||||
|
||||
The content of arguments separator does not matter, one should only
|
||||
check the pointer, use "----args-separator----" here to ease debug
|
||||
if someone misused it.
|
||||
|
||||
See BUG#25192
|
||||
*/
|
||||
const char *args_separator= "----args-separator----";
|
||||
const char *my_defaults_file=0;
|
||||
const char *my_defaults_group_suffix=0;
|
||||
char *my_defaults_extra_file=0;
|
||||
const char *my_defaults_extra_file=0;
|
||||
|
||||
static char my_defaults_file_buffer[FN_REFLEN];
|
||||
static char my_defaults_extra_file_buffer[FN_REFLEN];
|
||||
|
||||
static my_bool defaults_already_read= FALSE;
|
||||
|
||||
/* Which directories are searched for options (and in which order) */
|
||||
|
||||
@@ -95,7 +123,6 @@ static int search_default_file_with_ext(Process_option_func func,
|
||||
- Windows: GetWindowsDirectory()
|
||||
- Windows: C:/
|
||||
- Windows: Directory above where the executable is located
|
||||
- Netware: sys:/etc/
|
||||
- Unix: /etc/
|
||||
- Unix: /etc/mysql/
|
||||
- Unix: --sysconfdir=<path> (compile-time option)
|
||||
@@ -117,6 +144,33 @@ static const char **init_default_directories(MEM_ROOT *alloc);
|
||||
static char *remove_end_comment(char *ptr);
|
||||
|
||||
|
||||
/*
|
||||
Expand a file name so that the current working directory is added if
|
||||
the name is relative.
|
||||
|
||||
RETURNS
|
||||
0 All OK
|
||||
2 Out of memory or path to long
|
||||
3 Not able to get working directory
|
||||
*/
|
||||
|
||||
static int
|
||||
fn_expand(const char *filename, char *result_buf)
|
||||
{
|
||||
char dir[FN_REFLEN];
|
||||
const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
|
||||
DBUG_ENTER("fn_expand");
|
||||
DBUG_PRINT("enter", ("filename: %s, result_buf: 0x%lx",
|
||||
filename, (unsigned long) result_buf));
|
||||
if (my_getwd(dir, sizeof(dir), MYF(0)))
|
||||
DBUG_RETURN(3);
|
||||
DBUG_PRINT("debug", ("dir: %s", dir));
|
||||
if (fn_format(result_buf, filename, dir, NULL, flags) == NULL)
|
||||
DBUG_RETURN(2);
|
||||
DBUG_PRINT("return", ("result: %s", result_buf));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Process config files in default directories.
|
||||
|
||||
@@ -145,6 +199,7 @@ static char *remove_end_comment(char *ptr);
|
||||
0 ok
|
||||
1 given cinf_file doesn't exist
|
||||
2 out of memory
|
||||
3 Can't get current working directory
|
||||
|
||||
The global variable 'my_defaults_group_suffix' is updated with value for
|
||||
--defaults_group_suffix
|
||||
@@ -167,11 +222,23 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv,
|
||||
if (! my_defaults_group_suffix)
|
||||
my_defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV));
|
||||
|
||||
if (forced_extra_defaults)
|
||||
my_defaults_extra_file= (char *) forced_extra_defaults;
|
||||
|
||||
if (forced_default_file)
|
||||
my_defaults_file= forced_default_file;
|
||||
if (forced_extra_defaults && !defaults_already_read)
|
||||
{
|
||||
int error= fn_expand(forced_extra_defaults, my_defaults_extra_file_buffer);
|
||||
if (error)
|
||||
DBUG_RETURN(error);
|
||||
my_defaults_extra_file= my_defaults_extra_file_buffer;
|
||||
}
|
||||
|
||||
if (forced_default_file && !defaults_already_read)
|
||||
{
|
||||
int error= fn_expand(forced_default_file, my_defaults_file_buffer);
|
||||
if (error)
|
||||
DBUG_RETURN(error);
|
||||
my_defaults_file= my_defaults_file_buffer;
|
||||
}
|
||||
|
||||
defaults_already_read= TRUE;
|
||||
|
||||
/*
|
||||
We can only handle 'defaults-group-suffix' if we are called from
|
||||
@@ -214,15 +281,15 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv,
|
||||
group->type_names[group->count]= 0;
|
||||
}
|
||||
|
||||
if (forced_default_file)
|
||||
if (my_defaults_file)
|
||||
{
|
||||
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
|
||||
forced_default_file, 0)) < 0)
|
||||
my_defaults_file, 0)) < 0)
|
||||
goto err;
|
||||
if (error > 0)
|
||||
{
|
||||
fprintf(stderr, "Could not open required defaults file: %s\n",
|
||||
forced_default_file);
|
||||
my_defaults_file);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@@ -454,10 +521,11 @@ int my_load_defaults(const char *conf_file, const char **groups,
|
||||
goto err;
|
||||
res= (char**) (ptr+sizeof(alloc));
|
||||
res[0]= **argv; /* Copy program name */
|
||||
/* set arguments separator */
|
||||
res[1]= (char *)args_separator;
|
||||
for (i=2 ; i < (uint) *argc ; i++)
|
||||
res[i-1]=argv[0][i];
|
||||
res[i-1]=0; /* End pointer */
|
||||
(*argc)--;
|
||||
res[i]=argv[0][i];
|
||||
res[i]=0; /* End pointer */
|
||||
*argv=res;
|
||||
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
|
||||
if (default_directories)
|
||||
@@ -479,15 +547,19 @@ int my_load_defaults(const char *conf_file, const char **groups,
|
||||
ctx.args= &args;
|
||||
ctx.group= &group;
|
||||
|
||||
error= my_search_option_files(conf_file, argc, argv, &args_used,
|
||||
handle_default_option, (void *) &ctx,
|
||||
dirs);
|
||||
if ((error= my_search_option_files(conf_file, argc, argv, &args_used,
|
||||
handle_default_option, (void *) &ctx,
|
||||
dirs)))
|
||||
{
|
||||
free_root(&alloc,MYF(0));
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
/*
|
||||
Here error contains <> 0 only if we have a fully specified conf_file
|
||||
or a forced default file
|
||||
*/
|
||||
if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
|
||||
(args.elements + *argc +1) *sizeof(char*))))
|
||||
(args.elements + *argc + 1 + 1) *sizeof(char*))))
|
||||
goto err;
|
||||
res= (char**) (ptr+sizeof(alloc));
|
||||
|
||||
@@ -508,12 +580,16 @@ int my_load_defaults(const char *conf_file, const char **groups,
|
||||
--*argc; ++*argv; /* skip argument */
|
||||
}
|
||||
|
||||
if (*argc)
|
||||
memcpy((uchar*) (res+1+args.elements), (char*) ((*argv)+1),
|
||||
(*argc-1)*sizeof(char*));
|
||||
res[args.elements+ *argc]=0; /* last null */
|
||||
/* set arguments separator for arguments from config file and
|
||||
command line */
|
||||
res[args.elements+1]= (char *)args_separator;
|
||||
|
||||
(*argc)+=args.elements;
|
||||
if (*argc)
|
||||
memcpy((uchar*) (res+1+args.elements+1), (char*) ((*argv)+1),
|
||||
(*argc-1)*sizeof(char*));
|
||||
res[args.elements+ *argc+1]=0; /* last null */
|
||||
|
||||
(*argc)+=args.elements+1;
|
||||
*argv= (char**) res;
|
||||
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
|
||||
delete_dynamic(&args);
|
||||
@@ -523,15 +599,16 @@ int my_load_defaults(const char *conf_file, const char **groups,
|
||||
printf("%s would have been started with the following arguments:\n",
|
||||
**argv);
|
||||
for (i=1 ; i < *argc ; i++)
|
||||
printf("%s ", (*argv)[i]);
|
||||
if ((*argv)[i] != args_separator) /* skip arguments separator */
|
||||
printf("%s ", (*argv)[i]);
|
||||
puts("");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (error == 0 && default_directories)
|
||||
if (default_directories)
|
||||
*default_directories= dirs;
|
||||
|
||||
DBUG_RETURN(error);
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
|
||||
@@ -543,7 +620,7 @@ int my_load_defaults(const char *conf_file, const char **groups,
|
||||
void free_defaults(char **argv)
|
||||
{
|
||||
MEM_ROOT ptr;
|
||||
memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
|
||||
memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
|
||||
free_root(&ptr,MYF(0));
|
||||
}
|
||||
|
||||
@@ -654,7 +731,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
|
||||
static const char includedir_keyword[]= "includedir";
|
||||
static const char include_keyword[]= "include";
|
||||
const int max_recursion_level= 10;
|
||||
FILE *fp;
|
||||
MYSQL_FILE *fp;
|
||||
uint line=0;
|
||||
my_bool found_group=0;
|
||||
uint i;
|
||||
@@ -675,7 +752,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
|
||||
strmov(name,config_file);
|
||||
}
|
||||
fn_format(name,name,"","",4);
|
||||
#if !defined(__WIN__) && !defined(__NETWARE__)
|
||||
#if !defined(__WIN__)
|
||||
{
|
||||
MY_STAT stat_info;
|
||||
if (!my_stat(name,&stat_info,MYF(0)))
|
||||
@@ -694,10 +771,10 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
|
||||
if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
|
||||
return 1; /* Ignore wrong files */
|
||||
|
||||
while (fgets(buff, sizeof(buff) - 1, fp))
|
||||
while (mysql_file_fgets(buff, sizeof(buff) - 1, fp))
|
||||
{
|
||||
line++;
|
||||
/* Ignore comment and empty lines */
|
||||
@@ -887,11 +964,11 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
my_fclose(fp,MYF(0));
|
||||
mysql_file_fclose(fp, MYF(0));
|
||||
return(0);
|
||||
|
||||
err:
|
||||
my_fclose(fp,MYF(0));
|
||||
mysql_file_fclose(fp, MYF(0));
|
||||
return -1; /* Fatal error */
|
||||
}
|
||||
|
||||
@@ -921,7 +998,6 @@ static char *remove_end_comment(char *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#include <help_start.h>
|
||||
|
||||
void my_print_default_files(const char *conf_file)
|
||||
{
|
||||
@@ -1001,8 +1077,6 @@ void print_defaults(const char *conf_file, const char **groups)
|
||||
--defaults-extra-file=# Read this file after the global files are read.");
|
||||
}
|
||||
|
||||
#include <help_end.h>
|
||||
|
||||
|
||||
static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
|
||||
{
|
||||
@@ -1117,10 +1191,6 @@ static const char **init_default_directories(MEM_ROOT *alloc)
|
||||
errors += add_directory(alloc, fname_buffer, dirs);
|
||||
}
|
||||
|
||||
#elif defined(__NETWARE__)
|
||||
|
||||
errors += add_directory(alloc, "sys:/etc/", dirs);
|
||||
|
||||
#else
|
||||
|
||||
errors += add_directory(alloc, "/etc/", dirs);
|
||||
@@ -1139,7 +1209,7 @@ static const char **init_default_directories(MEM_ROOT *alloc)
|
||||
/* Placeholder for --defaults-extra-file=<path> */
|
||||
errors += add_directory(alloc, "", dirs);
|
||||
|
||||
#if !defined(__WIN__) && !defined(__NETWARE__)
|
||||
#if !defined(__WIN__)
|
||||
errors += add_directory(alloc, "~/", dirs);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
/* Copyright (C) 2005 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "my_global.h"
|
||||
#include "mysys_priv.h"
|
||||
#include "m_string.h"
|
||||
#include <my_dir.h>
|
||||
|
||||
#define BUFF_SIZE 1024
|
||||
#define RESERVE 1024 /* Extend buffer with this extent */
|
||||
|
||||
#ifdef __WIN__
|
||||
#define NEWLINE "\r\n"
|
||||
#define NEWLINE_LEN 2
|
||||
#else
|
||||
#define NEWLINE "\n"
|
||||
#define NEWLINE_LEN 1
|
||||
#endif
|
||||
|
||||
static char *add_option(char *dst, const char *option_value,
|
||||
const char *option, int remove_option);
|
||||
|
||||
|
||||
/*
|
||||
Add/remove option to the option file section.
|
||||
|
||||
SYNOPSYS
|
||||
modify_defaults_file()
|
||||
file_location The location of configuration file to edit
|
||||
option The name of the option to look for (can be NULL)
|
||||
option value The value of the option we would like to set (can be NULL)
|
||||
section_name The name of the section (must be NOT NULL)
|
||||
remove_option This defines what we want to remove:
|
||||
- MY_REMOVE_NONE -- nothing to remove;
|
||||
- MY_REMOVE_OPTION -- remove the specified option;
|
||||
- MY_REMOVE_SECTION -- remove the specified section;
|
||||
IMPLEMENTATION
|
||||
We open the option file first, then read the file line-by-line,
|
||||
looking for the section we need. At the same time we put these lines
|
||||
into a buffer. Then we look for the option within this section and
|
||||
change/remove it. In the end we get a buffer with modified version of the
|
||||
file. Then we write it to the file, truncate it if needed and close it.
|
||||
Note that there is a small time gap, when the file is incomplete,
|
||||
and this theoretically might introduce a problem.
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - some error has occured. Probably due to the lack of resourses
|
||||
2 - cannot open the file
|
||||
*/
|
||||
|
||||
int modify_defaults_file(const char *file_location, const char *option,
|
||||
const char *option_value,
|
||||
const char *section_name, int remove_option)
|
||||
{
|
||||
FILE *cnf_file;
|
||||
MY_STAT file_stat;
|
||||
char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
|
||||
size_t opt_len= 0, optval_len= 0, sect_len, new_opt_len, reserve_extended;
|
||||
uint nr_newlines= 0, buffer_size;
|
||||
my_bool in_section= FALSE, opt_applied= 0;
|
||||
int reserve_occupied= 0;
|
||||
DBUG_ENTER("modify_defaults_file");
|
||||
|
||||
if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0))))
|
||||
DBUG_RETURN(2);
|
||||
|
||||
/* my_fstat doesn't use the flag parameter */
|
||||
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
|
||||
goto malloc_err;
|
||||
|
||||
if (option && option_value)
|
||||
{
|
||||
opt_len= strlen(option);
|
||||
optval_len= strlen(option_value);
|
||||
}
|
||||
|
||||
new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
|
||||
|
||||
/* calculate the size of the buffer we need */
|
||||
reserve_extended= (opt_len +
|
||||
1 + /* For '=' char */
|
||||
optval_len + /* Option value len */
|
||||
NEWLINE_LEN + /* Space for newline */
|
||||
RESERVE); /* Some additional space */
|
||||
|
||||
buffer_size= (file_stat.st_size +
|
||||
1); /* The ending zero */
|
||||
|
||||
/*
|
||||
Reserve space to read the contents of the file and some more
|
||||
for the option we want to add.
|
||||
*/
|
||||
if (!(file_buffer= (char*) my_malloc(buffer_size + reserve_extended,
|
||||
MYF(MY_WME))))
|
||||
goto malloc_err;
|
||||
|
||||
sect_len= strlen(section_name);
|
||||
|
||||
for (dst_ptr= file_buffer; fgets(linebuff, BUFF_SIZE, cnf_file); )
|
||||
{
|
||||
/* Skip over whitespaces */
|
||||
for (src_ptr= linebuff; my_isspace(&my_charset_latin1, *src_ptr);
|
||||
src_ptr++)
|
||||
{}
|
||||
|
||||
if (!*src_ptr) /* Empty line */
|
||||
{
|
||||
nr_newlines++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* correct the option (if requested) */
|
||||
if (option && in_section && !strncmp(src_ptr, option, opt_len) &&
|
||||
(*(src_ptr + opt_len) == '=' ||
|
||||
my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
|
||||
*(src_ptr + opt_len) == '\0'))
|
||||
{
|
||||
char *old_src_ptr= src_ptr;
|
||||
src_ptr= strend(src_ptr+ opt_len); /* Find the end of the line */
|
||||
|
||||
/* could be negative */
|
||||
reserve_occupied+= (int) new_opt_len - (int) (src_ptr - old_src_ptr);
|
||||
if (reserve_occupied >= (int) reserve_extended)
|
||||
{
|
||||
reserve_extended= (uint) reserve_occupied + RESERVE;
|
||||
if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size +
|
||||
reserve_extended,
|
||||
MYF(MY_WME|MY_FREE_ON_ERROR))))
|
||||
goto malloc_err;
|
||||
}
|
||||
opt_applied= 1;
|
||||
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we are going to the new group and have an option to apply, do
|
||||
it now. If we are removing a single option or the whole section
|
||||
this will only trigger opt_applied flag.
|
||||
*/
|
||||
|
||||
if (in_section && !opt_applied && *src_ptr == '[')
|
||||
{
|
||||
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
|
||||
opt_applied= 1; /* set the flag to do write() later */
|
||||
reserve_occupied= new_opt_len+ opt_len + 1 + NEWLINE_LEN;
|
||||
}
|
||||
|
||||
for (; nr_newlines; nr_newlines--)
|
||||
dst_ptr= strmov(dst_ptr, NEWLINE);
|
||||
|
||||
/* Skip the section if MY_REMOVE_SECTION was given */
|
||||
if (!in_section || remove_option != MY_REMOVE_SECTION)
|
||||
dst_ptr= strmov(dst_ptr, linebuff);
|
||||
}
|
||||
/* Look for a section */
|
||||
if (*src_ptr == '[')
|
||||
{
|
||||
/* Copy the line to the buffer */
|
||||
if (!strncmp(++src_ptr, section_name, sect_len))
|
||||
{
|
||||
src_ptr+= sect_len;
|
||||
/* Skip over whitespaces. They are allowed after section name */
|
||||
for (; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++)
|
||||
{}
|
||||
|
||||
if (*src_ptr != ']')
|
||||
{
|
||||
in_section= FALSE;
|
||||
continue; /* Missing closing parenthesis. Assume this was no group */
|
||||
}
|
||||
|
||||
if (remove_option == MY_REMOVE_SECTION)
|
||||
dst_ptr= dst_ptr - strlen(linebuff);
|
||||
|
||||
in_section= TRUE;
|
||||
}
|
||||
else
|
||||
in_section= FALSE; /* mark that this section is of no interest to us */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
File ended. Apply an option or set opt_applied flag (in case of
|
||||
MY_REMOVE_SECTION) so that the changes are saved. Do not do anything
|
||||
if we are removing non-existent option.
|
||||
*/
|
||||
|
||||
if (!opt_applied && in_section && (remove_option != MY_REMOVE_OPTION))
|
||||
{
|
||||
/* New option still remains to apply at the end */
|
||||
if (!remove_option && *(dst_ptr - 1) != '\n')
|
||||
dst_ptr= strmov(dst_ptr, NEWLINE);
|
||||
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
|
||||
opt_applied= 1;
|
||||
}
|
||||
for (; nr_newlines; nr_newlines--)
|
||||
dst_ptr= strmov(dst_ptr, NEWLINE);
|
||||
|
||||
if (opt_applied)
|
||||
{
|
||||
/* Don't write the file if there are no changes to be made */
|
||||
if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
|
||||
MYF(MY_WME)) ||
|
||||
my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
|
||||
my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
|
||||
MYF(MY_NABP)))
|
||||
goto err;
|
||||
}
|
||||
if (my_fclose(cnf_file, MYF(MY_WME)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
my_free(file_buffer, MYF(0));
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
my_free(file_buffer, MYF(0));
|
||||
malloc_err:
|
||||
my_fclose(cnf_file, MYF(0));
|
||||
DBUG_RETURN(1); /* out of resources */
|
||||
}
|
||||
|
||||
|
||||
static char *add_option(char *dst, const char *option_value,
|
||||
const char *option, int remove_option)
|
||||
{
|
||||
if (!remove_option)
|
||||
{
|
||||
dst= strmov(dst, option);
|
||||
if (*option_value)
|
||||
{
|
||||
*dst++= '=';
|
||||
dst= strmov(dst, option_value);
|
||||
}
|
||||
/* add a newline */
|
||||
dst= strmov(dst, NEWLINE);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#ifndef SHARED_LIBRARY
|
||||
|
||||
const char * NEAR globerrs[GLOBERRS]=
|
||||
const char *globerrs[GLOBERRS]=
|
||||
{
|
||||
"Can't create/write to file '%s' (Errcode: %d)",
|
||||
"Error reading file '%s' (Errcode: %d)",
|
||||
@@ -52,6 +52,7 @@ const char * NEAR globerrs[GLOBERRS]=
|
||||
"File '%s' (fileno: %d) was not closed",
|
||||
"Can't change ownership of the file '%s' (Errcode: %d)",
|
||||
"Can't change permissions of the file '%s' (Errcode: %d)",
|
||||
"Can't seek in file '%s' (Errcode: %d)"
|
||||
};
|
||||
|
||||
void init_glob_errs(void)
|
||||
@@ -94,6 +95,7 @@ void init_glob_errs()
|
||||
EE(EE_FILE_NOT_CLOSED) = "File '%s' (fileno: %d) was not closed";
|
||||
EE(EE_CHANGE_OWNERSHIP) = "Can't change ownership of the file '%s' (Errcode: %d)";
|
||||
EE(EE_CHANGE_PERMISSIONS) = "Can't change permissions of the file '%s' (Errcode: %d)";
|
||||
EE(EE_CANT_SEEK) = "Can't seek in file '%s' (Errcode: %d)";
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -108,5 +110,10 @@ void wait_for_free_space(const char *filename, int errors)
|
||||
MYF(ME_BELL | ME_NOREFRESH),
|
||||
MY_WAIT_FOR_USER_TO_FIX_PANIC,
|
||||
MY_WAIT_GIVE_USER_A_MESSAGE * MY_WAIT_FOR_USER_TO_FIX_PANIC );
|
||||
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
|
||||
(void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
|
||||
}
|
||||
|
||||
const char **get_global_errmsgs()
|
||||
{
|
||||
return globerrs;
|
||||
}
|
||||
|
||||
+50
-13
@@ -33,16 +33,18 @@ typedef struct st_hash_info {
|
||||
uchar *data; /* data for current entry */
|
||||
} HASH_LINK;
|
||||
|
||||
static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength);
|
||||
static uint my_hash_mask(my_hash_value_type hashnr,
|
||||
size_t buffmax, size_t maxlength);
|
||||
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
|
||||
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
|
||||
size_t length);
|
||||
|
||||
static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
|
||||
static my_hash_value_type calc_hash(const HASH *hash,
|
||||
const uchar *key, size_t length)
|
||||
{
|
||||
ulong nr1=1, nr2=4;
|
||||
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
|
||||
return nr1;
|
||||
return (my_hash_value_type)nr1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,8 +67,6 @@ static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
|
||||
@param[in] get_key get the key for the hash
|
||||
@param[in] free_element pointer to the function that
|
||||
does cleanup
|
||||
@param[in] CALLER_INFO_PROTO flag that define the behaviour
|
||||
of the hash
|
||||
@return inidicates success or failure of initialization
|
||||
@retval 0 success
|
||||
@retval 1 failure
|
||||
@@ -75,7 +75,7 @@ my_bool
|
||||
_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
|
||||
ulong size, size_t key_offset, size_t key_length,
|
||||
my_hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO)
|
||||
void (*free_element)(void*), uint flags)
|
||||
{
|
||||
DBUG_ENTER("my_hash_init");
|
||||
DBUG_PRINT("enter",("hash: 0x%lx size: %u", (long) hash, (uint) size));
|
||||
@@ -179,7 +179,8 @@ my_hash_key(const HASH *hash, const uchar *record, size_t *length,
|
||||
|
||||
/* Calculate pos according to keys */
|
||||
|
||||
static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength)
|
||||
static uint my_hash_mask(my_hash_value_type hashnr, size_t buffmax,
|
||||
size_t maxlength)
|
||||
{
|
||||
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
|
||||
return (hashnr & ((buffmax >> 1) -1));
|
||||
@@ -200,7 +201,7 @@ static
|
||||
#if !defined(__USLC__) && !defined(__sgi)
|
||||
inline
|
||||
#endif
|
||||
unsigned int rec_hashnr(HASH *hash,const uchar *record)
|
||||
my_hash_value_type rec_hashnr(HASH *hash,const uchar *record)
|
||||
{
|
||||
size_t length;
|
||||
uchar *key= (uchar*) my_hash_key(hash, record, &length, 0);
|
||||
@@ -214,6 +215,23 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length)
|
||||
return my_hash_first(hash, key, length, &state);
|
||||
}
|
||||
|
||||
uchar* my_hash_search_using_hash_value(const HASH *hash,
|
||||
my_hash_value_type hash_value,
|
||||
const uchar *key,
|
||||
size_t length)
|
||||
{
|
||||
HASH_SEARCH_STATE state;
|
||||
return my_hash_first_from_hash_value(hash, hash_value,
|
||||
key, length, &state);
|
||||
}
|
||||
|
||||
my_hash_value_type my_calc_hash(const HASH *hash,
|
||||
const uchar *key, size_t length)
|
||||
{
|
||||
return calc_hash(hash, key, length ? length : hash->key_length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Search after a record based on a key
|
||||
|
||||
@@ -223,15 +241,32 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length)
|
||||
|
||||
uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length,
|
||||
HASH_SEARCH_STATE *current_record)
|
||||
{
|
||||
uchar *res;
|
||||
if (my_hash_inited(hash))
|
||||
res= my_hash_first_from_hash_value(hash,
|
||||
calc_hash(hash, key, length ? length : hash->key_length),
|
||||
key, length, current_record);
|
||||
else
|
||||
res= 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
uchar* my_hash_first_from_hash_value(const HASH *hash,
|
||||
my_hash_value_type hash_value,
|
||||
const uchar *key,
|
||||
size_t length,
|
||||
HASH_SEARCH_STATE *current_record)
|
||||
{
|
||||
HASH_LINK *pos;
|
||||
uint flag,idx;
|
||||
DBUG_ENTER("my_hash_first");
|
||||
DBUG_ENTER("my_hash_first_from_hash_value");
|
||||
|
||||
flag=1;
|
||||
if (hash->records)
|
||||
{
|
||||
idx= my_hash_mask(calc_hash(hash, key, length ? length : hash->key_length),
|
||||
idx= my_hash_mask(hash_value,
|
||||
hash->blength, hash->records);
|
||||
do
|
||||
{
|
||||
@@ -331,7 +366,8 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
|
||||
my_bool my_hash_insert(HASH *info, const uchar *record)
|
||||
{
|
||||
int flag;
|
||||
size_t idx,halfbuff,hash_nr,first_index;
|
||||
size_t idx,halfbuff,first_index;
|
||||
my_hash_value_type hash_nr;
|
||||
uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2);
|
||||
HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos;
|
||||
|
||||
@@ -467,7 +503,8 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
|
||||
|
||||
my_bool my_hash_delete(HASH *hash, uchar *record)
|
||||
{
|
||||
uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
|
||||
uint blength,pos2,idx,empty_index;
|
||||
my_hash_value_type pos_hashnr, lastpos_hashnr;
|
||||
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
|
||||
DBUG_ENTER("my_hash_delete");
|
||||
if (!hash->records)
|
||||
@@ -541,7 +578,7 @@ my_bool my_hash_delete(HASH *hash, uchar *record)
|
||||
pos->next=empty_index;
|
||||
|
||||
exit:
|
||||
VOID(pop_dynamic(&hash->array));
|
||||
(void) pop_dynamic(&hash->array);
|
||||
if (hash->free)
|
||||
(*hash->free)((uchar*) record);
|
||||
DBUG_RETURN(0);
|
||||
|
||||
@@ -0,0 +1,527 @@
|
||||
/* QQ: TODO multi-pinbox */
|
||||
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
wait-free concurrent allocator based on pinning addresses
|
||||
|
||||
It works as follows: every thread (strictly speaking - every CPU, but
|
||||
it's too difficult to do) has a small array of pointers. They're called
|
||||
"pins". Before using an object its address must be stored in this array
|
||||
(pinned). When an object is no longer necessary its address must be
|
||||
removed from this array (unpinned). When a thread wants to free() an
|
||||
object it scans all pins of all threads to see if somebody has this
|
||||
object pinned. If yes - the object is not freed (but stored in a
|
||||
"purgatory"). To reduce the cost of a single free() pins are not scanned
|
||||
on every free() but only added to (thread-local) purgatory. On every
|
||||
LF_PURGATORY_SIZE free() purgatory is scanned and all unpinned objects
|
||||
are freed.
|
||||
|
||||
Pins are used to solve ABA problem. To use pins one must obey
|
||||
a pinning protocol:
|
||||
|
||||
1. Let's assume that PTR is a shared pointer to an object. Shared means
|
||||
that any thread may modify it anytime to point to a different object
|
||||
and free the old object. Later the freed object may be potentially
|
||||
allocated by another thread. If we're unlucky that other thread may
|
||||
set PTR to point to this object again. This is ABA problem.
|
||||
2. Create a local pointer LOCAL_PTR.
|
||||
3. Pin the PTR in a loop:
|
||||
do
|
||||
{
|
||||
LOCAL_PTR= PTR;
|
||||
pin(PTR, PIN_NUMBER);
|
||||
} while (LOCAL_PTR != PTR)
|
||||
4. It is guaranteed that after the loop has ended, LOCAL_PTR
|
||||
points to an object (or NULL, if PTR may be NULL), that
|
||||
will never be freed. It is not guaranteed though
|
||||
that LOCAL_PTR == PTR (as PTR can change any time)
|
||||
5. When done working with the object, remove the pin:
|
||||
unpin(PIN_NUMBER)
|
||||
6. When copying pins (as in the list traversing loop:
|
||||
pin(CUR, 1);
|
||||
while ()
|
||||
{
|
||||
do // standard
|
||||
{ // pinning
|
||||
NEXT=CUR->next; // loop
|
||||
pin(NEXT, 0); // see #3
|
||||
} while (NEXT != CUR->next); // above
|
||||
...
|
||||
...
|
||||
CUR=NEXT;
|
||||
pin(CUR, 1); // copy pin[0] to pin[1]
|
||||
}
|
||||
which keeps CUR address constantly pinned), note than pins may be
|
||||
copied only upwards (!!!), that is pin[N] to pin[M], M > N.
|
||||
7. Don't keep the object pinned longer than necessary - the number of
|
||||
pins you have is limited (and small), keeping an object pinned
|
||||
prevents its reuse and cause unnecessary mallocs.
|
||||
|
||||
Explanations:
|
||||
|
||||
3. The loop is important. The following can occur:
|
||||
thread1> LOCAL_PTR= PTR
|
||||
thread2> free(PTR); PTR=0;
|
||||
thread1> pin(PTR, PIN_NUMBER);
|
||||
now thread1 cannot access LOCAL_PTR, even if it's pinned,
|
||||
because it points to a freed memory. That is, it *must*
|
||||
verify that it has indeed pinned PTR, the shared pointer.
|
||||
|
||||
6. When a thread wants to free some LOCAL_PTR, and it scans
|
||||
all lists of pins to see whether it's pinned, it does it
|
||||
upwards, from low pin numbers to high. Thus another thread
|
||||
must copy an address from one pin to another in the same
|
||||
direction - upwards, otherwise the scanning thread may
|
||||
miss it.
|
||||
|
||||
Implementation details:
|
||||
|
||||
Pins are given away from a "pinbox". Pinbox is stack-based allocator.
|
||||
It used dynarray for storing pins, new elements are allocated by dynarray
|
||||
as necessary, old are pushed in the stack for reuse. ABA is solved by
|
||||
versioning a pointer - because we use an array, a pointer to pins is 16 bit,
|
||||
upper 16 bits are used for a version.
|
||||
|
||||
It is assumed that pins belong to a THD and are not transferable
|
||||
between THD's (LF_PINS::stack_ends_here being a primary reason
|
||||
for this limitation).
|
||||
*/
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <lf.h>
|
||||
|
||||
#define LF_PINBOX_MAX_PINS 65536
|
||||
|
||||
static void _lf_pinbox_real_free(LF_PINS *pins);
|
||||
|
||||
/*
|
||||
Initialize a pinbox. Normally called from lf_alloc_init.
|
||||
See the latter for details.
|
||||
*/
|
||||
void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
|
||||
lf_pinbox_free_func *free_func, void *free_func_arg)
|
||||
{
|
||||
DBUG_ASSERT(free_ptr_offset % sizeof(void *) == 0);
|
||||
compile_time_assert(sizeof(LF_PINS) == 64);
|
||||
lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS));
|
||||
pinbox->pinstack_top_ver= 0;
|
||||
pinbox->pins_in_array= 0;
|
||||
pinbox->free_ptr_offset= free_ptr_offset;
|
||||
pinbox->free_func= free_func;
|
||||
pinbox->free_func_arg= free_func_arg;
|
||||
}
|
||||
|
||||
void lf_pinbox_destroy(LF_PINBOX *pinbox)
|
||||
{
|
||||
lf_dynarray_destroy(&pinbox->pinarray);
|
||||
}
|
||||
|
||||
/*
|
||||
Get pins from a pinbox. Usually called via lf_alloc_get_pins() or
|
||||
lf_hash_get_pins().
|
||||
|
||||
SYNOPSYS
|
||||
pinbox -
|
||||
|
||||
DESCRIPTION
|
||||
get a new LF_PINS structure from a stack of unused pins,
|
||||
or allocate a new one out of dynarray.
|
||||
|
||||
NOTE
|
||||
It is assumed that pins belong to a thread and are not transferable
|
||||
between threads.
|
||||
*/
|
||||
LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
|
||||
{
|
||||
uint32 pins, next, top_ver;
|
||||
LF_PINS *el;
|
||||
/*
|
||||
We have an array of max. 64k elements.
|
||||
The highest index currently allocated is pinbox->pins_in_array.
|
||||
Freed elements are in a lifo stack, pinstack_top_ver.
|
||||
pinstack_top_ver is 32 bits; 16 low bits are the index in the
|
||||
array, to the first element of the list. 16 high bits are a version
|
||||
(every time the 16 low bits are updated, the 16 high bits are
|
||||
incremented). Versioniong prevents the ABA problem.
|
||||
*/
|
||||
top_ver= pinbox->pinstack_top_ver;
|
||||
do
|
||||
{
|
||||
if (!(pins= top_ver % LF_PINBOX_MAX_PINS))
|
||||
{
|
||||
/* the stack of free elements is empty */
|
||||
pins= my_atomic_add32((int32 volatile*) &pinbox->pins_in_array, 1)+1;
|
||||
if (unlikely(pins >= LF_PINBOX_MAX_PINS))
|
||||
return 0;
|
||||
/*
|
||||
note that the first allocated element has index 1 (pins==1).
|
||||
index 0 is reserved to mean "NULL pointer"
|
||||
*/
|
||||
el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins);
|
||||
if (unlikely(!el))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins);
|
||||
next= el->link;
|
||||
} while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
|
||||
(int32*) &top_ver,
|
||||
top_ver-pins+next+LF_PINBOX_MAX_PINS));
|
||||
/*
|
||||
set el->link to the index of el in the dynarray (el->link has two usages:
|
||||
- if element is allocated, it's its own index
|
||||
- if element is free, it's its next element in the free stack
|
||||
*/
|
||||
el->link= pins;
|
||||
el->purgatory_count= 0;
|
||||
el->pinbox= pinbox;
|
||||
el->stack_ends_here= & my_thread_var->stack_ends_here;
|
||||
return el;
|
||||
}
|
||||
|
||||
/*
|
||||
Put pins back to a pinbox. Usually called via lf_alloc_put_pins() or
|
||||
lf_hash_put_pins().
|
||||
|
||||
DESCRIPTION
|
||||
empty the purgatory (XXX deadlock warning below!),
|
||||
push LF_PINS structure to a stack
|
||||
*/
|
||||
void _lf_pinbox_put_pins(LF_PINS *pins)
|
||||
{
|
||||
LF_PINBOX *pinbox= pins->pinbox;
|
||||
uint32 top_ver, nr;
|
||||
nr= pins->link;
|
||||
#ifdef MY_LF_EXTRA_DEBUG
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
DBUG_ASSERT(pins->pin[i] == 0);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
XXX this will deadlock if other threads will wait for
|
||||
the caller to do something after _lf_pinbox_put_pins(),
|
||||
and they would have pinned addresses that the caller wants to free.
|
||||
Thus: only free pins when all work is done and nobody can wait for you!!!
|
||||
*/
|
||||
while (pins->purgatory_count)
|
||||
{
|
||||
_lf_pinbox_real_free(pins);
|
||||
if (pins->purgatory_count)
|
||||
{
|
||||
my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock);
|
||||
pthread_yield();
|
||||
my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock);
|
||||
}
|
||||
}
|
||||
top_ver= pinbox->pinstack_top_ver;
|
||||
do
|
||||
{
|
||||
pins->link= top_ver % LF_PINBOX_MAX_PINS;
|
||||
} while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
|
||||
(int32*) &top_ver,
|
||||
top_ver-pins->link+nr+LF_PINBOX_MAX_PINS));
|
||||
return;
|
||||
}
|
||||
|
||||
static int ptr_cmp(void **a, void **b)
|
||||
{
|
||||
return *a < *b ? -1 : *a == *b ? 0 : 1;
|
||||
}
|
||||
|
||||
#define add_to_purgatory(PINS, ADDR) \
|
||||
do \
|
||||
{ \
|
||||
*(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \
|
||||
(PINS)->purgatory; \
|
||||
(PINS)->purgatory= (ADDR); \
|
||||
(PINS)->purgatory_count++; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
Free an object allocated via pinbox allocator
|
||||
|
||||
DESCRIPTION
|
||||
add an object to purgatory. if necessary, call _lf_pinbox_real_free()
|
||||
to actually free something.
|
||||
*/
|
||||
void _lf_pinbox_free(LF_PINS *pins, void *addr)
|
||||
{
|
||||
add_to_purgatory(pins, addr);
|
||||
if (pins->purgatory_count % LF_PURGATORY_SIZE)
|
||||
_lf_pinbox_real_free(pins);
|
||||
}
|
||||
|
||||
struct st_harvester {
|
||||
void **granary;
|
||||
int npins;
|
||||
};
|
||||
|
||||
/*
|
||||
callback for _lf_dynarray_iterate:
|
||||
scan all pins of all threads and accumulate all pins
|
||||
*/
|
||||
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
|
||||
{
|
||||
int i;
|
||||
LF_PINS *el_end= el+min(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
|
||||
for (; el < el_end; el++)
|
||||
{
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
{
|
||||
void *p= el->pin[i];
|
||||
if (p)
|
||||
*hv->granary++= p;
|
||||
}
|
||||
}
|
||||
/*
|
||||
hv->npins may become negative below, but it means that
|
||||
we're on the last dynarray page and harvest_pins() won't be
|
||||
called again. We don't bother to make hv->npins() correct
|
||||
(that is 0) in this case.
|
||||
*/
|
||||
hv->npins-= LF_DYNARRAY_LEVEL_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
callback for _lf_dynarray_iterate:
|
||||
scan all pins of all threads and see if addr is present there
|
||||
*/
|
||||
static int match_pins(LF_PINS *el, void *addr)
|
||||
{
|
||||
int i;
|
||||
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
|
||||
for (; el < el_end; el++)
|
||||
for (i= 0; i < LF_PINBOX_PINS; i++)
|
||||
if (el->pin[i] == addr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if STACK_DIRECTION < 0
|
||||
#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
|
||||
#else
|
||||
#define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR))
|
||||
#endif
|
||||
|
||||
#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset)))
|
||||
#define anext_node(X) next_node(&allocator->pinbox, (X))
|
||||
|
||||
/*
|
||||
Scan the purgatory and free everything that can be freed
|
||||
*/
|
||||
static void _lf_pinbox_real_free(LF_PINS *pins)
|
||||
{
|
||||
int npins, alloca_size;
|
||||
void *list, **addr;
|
||||
void *first= NULL, *last= NULL;
|
||||
LF_PINBOX *pinbox= pins->pinbox;
|
||||
|
||||
npins= pinbox->pins_in_array+1;
|
||||
|
||||
#ifdef HAVE_ALLOCA
|
||||
alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
|
||||
/* create a sorted list of pinned addresses, to speed up searches */
|
||||
if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
|
||||
{
|
||||
struct st_harvester hv;
|
||||
addr= (void **) alloca(alloca_size);
|
||||
hv.granary= addr;
|
||||
hv.npins= npins;
|
||||
/* scan the dynarray and accumulate all pinned addresses */
|
||||
_lf_dynarray_iterate(&pinbox->pinarray,
|
||||
(lf_dynarray_func)harvest_pins, &hv);
|
||||
|
||||
npins= hv.granary-addr;
|
||||
/* and sort them */
|
||||
if (npins)
|
||||
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
addr= 0;
|
||||
|
||||
list= pins->purgatory;
|
||||
pins->purgatory= 0;
|
||||
pins->purgatory_count= 0;
|
||||
while (list)
|
||||
{
|
||||
void *cur= list;
|
||||
list= *(void **)((char *)cur+pinbox->free_ptr_offset);
|
||||
if (npins)
|
||||
{
|
||||
if (addr) /* use binary search */
|
||||
{
|
||||
void **a, **b, **c;
|
||||
for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
|
||||
if (cur == *c)
|
||||
a= b= c;
|
||||
else if (cur > *c)
|
||||
a= c;
|
||||
else
|
||||
b= c;
|
||||
if (cur == *a || cur == *b)
|
||||
goto found;
|
||||
}
|
||||
else /* no alloca - no cookie. linear search here */
|
||||
{
|
||||
if (_lf_dynarray_iterate(&pinbox->pinarray,
|
||||
(lf_dynarray_func)match_pins, cur))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
/* not pinned - freeing */
|
||||
if (last)
|
||||
last= next_node(pinbox, last)= (uchar *)cur;
|
||||
else
|
||||
first= last= (uchar *)cur;
|
||||
continue;
|
||||
found:
|
||||
/* pinned - keeping */
|
||||
add_to_purgatory(pins, cur);
|
||||
}
|
||||
if (last)
|
||||
pinbox->free_func(first, last, pinbox->free_func_arg);
|
||||
}
|
||||
|
||||
/* lock-free memory allocator for fixed-size objects */
|
||||
|
||||
LF_REQUIRE_PINS(1)
|
||||
|
||||
/*
|
||||
callback for _lf_pinbox_real_free to free a list of unpinned objects -
|
||||
add it back to the allocator stack
|
||||
|
||||
DESCRIPTION
|
||||
'first' and 'last' are the ends of the linked list of nodes:
|
||||
first->el->el->....->el->last. Use first==last to free only one element.
|
||||
*/
|
||||
static void alloc_free(uchar *first,
|
||||
uchar volatile *last,
|
||||
LF_ALLOCATOR *allocator)
|
||||
{
|
||||
/*
|
||||
we need a union here to access type-punned pointer reliably.
|
||||
otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
|
||||
*/
|
||||
union { uchar * node; void *ptr; } tmp;
|
||||
tmp.node= allocator->top;
|
||||
do
|
||||
{
|
||||
anext_node(last)= tmp.node;
|
||||
} while (!my_atomic_casptr((void **)(char *)&allocator->top,
|
||||
(void **)&tmp.ptr, first) && LF_BACKOFF);
|
||||
}
|
||||
|
||||
/*
|
||||
initialize lock-free allocator
|
||||
|
||||
SYNOPSYS
|
||||
allocator -
|
||||
size a size of an object to allocate
|
||||
free_ptr_offset an offset inside the object to a sizeof(void *)
|
||||
memory that is guaranteed to be unused after
|
||||
the object is put in the purgatory. Unused by ANY
|
||||
thread, not only the purgatory owner.
|
||||
This memory will be used to link waiting-to-be-freed
|
||||
objects in a purgatory list.
|
||||
*/
|
||||
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
|
||||
{
|
||||
lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
|
||||
(lf_pinbox_free_func *)alloc_free, allocator);
|
||||
allocator->top= 0;
|
||||
allocator->mallocs= 0;
|
||||
allocator->element_size= size;
|
||||
DBUG_ASSERT(size >= sizeof(void*) + free_ptr_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
destroy the allocator, free everything that's in it
|
||||
|
||||
NOTE
|
||||
As every other init/destroy function here and elsewhere it
|
||||
is not thread safe. No, this function is no different, ensure
|
||||
that no thread needs the allocator before destroying it.
|
||||
We are not responsible for any damage that may be caused by
|
||||
accessing the allocator when it is being or has been destroyed.
|
||||
Oh yes, and don't put your cat in a microwave.
|
||||
*/
|
||||
void lf_alloc_destroy(LF_ALLOCATOR *allocator)
|
||||
{
|
||||
uchar *node= allocator->top;
|
||||
while (node)
|
||||
{
|
||||
uchar *tmp= anext_node(node);
|
||||
my_free(node);
|
||||
node= tmp;
|
||||
}
|
||||
lf_pinbox_destroy(&allocator->pinbox);
|
||||
allocator->top= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Allocate and return an new object.
|
||||
|
||||
DESCRIPTION
|
||||
Pop an unused object from the stack or malloc it is the stack is empty.
|
||||
pin[0] is used, it's removed on return.
|
||||
*/
|
||||
void *_lf_alloc_new(LF_PINS *pins)
|
||||
{
|
||||
LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
|
||||
uchar *node;
|
||||
for (;;)
|
||||
{
|
||||
do
|
||||
{
|
||||
node= allocator->top;
|
||||
_lf_pin(pins, 0, node);
|
||||
} while (node != allocator->top && LF_BACKOFF);
|
||||
if (!node)
|
||||
{
|
||||
node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
|
||||
#ifdef MY_LF_EXTRA_DEBUG
|
||||
if (likely(node != 0))
|
||||
my_atomic_add32(&allocator->mallocs, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (my_atomic_casptr((void **)(char *)&allocator->top,
|
||||
(void *)&node, anext_node(node)))
|
||||
break;
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
count the number of objects in a pool.
|
||||
|
||||
NOTE
|
||||
This is NOT thread-safe !!!
|
||||
*/
|
||||
uint lf_alloc_pool_count(LF_ALLOCATOR *allocator)
|
||||
{
|
||||
uint i;
|
||||
uchar *node;
|
||||
for (node= allocator->top, i= 0; node; node= anext_node(node), i++)
|
||||
/* no op */;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/* Copyright (C) 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Analog of DYNAMIC_ARRAY that never reallocs
|
||||
(so no pointer into the array may ever become invalid).
|
||||
|
||||
Memory is allocated in non-contiguous chunks.
|
||||
This data structure is not space efficient for sparse arrays.
|
||||
|
||||
Every element is aligned to sizeof(element) boundary
|
||||
(to avoid false sharing if element is big enough).
|
||||
|
||||
LF_DYNARRAY is a recursive structure. On the zero level
|
||||
LF_DYNARRAY::level[0] it's an array of LF_DYNARRAY_LEVEL_LENGTH elements,
|
||||
on the first level it's an array of LF_DYNARRAY_LEVEL_LENGTH pointers
|
||||
to arrays of elements, on the second level it's an array of pointers
|
||||
to arrays of pointers to arrays of elements. And so on.
|
||||
|
||||
With four levels the number of elements is limited to 4311810304
|
||||
(but as in all functions index is uint, the real limit is 2^32-1)
|
||||
|
||||
Actually, it's wait-free, not lock-free ;-)
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_sys.h>
|
||||
#include <lf.h>
|
||||
|
||||
void lf_dynarray_init(LF_DYNARRAY *array, uint element_size)
|
||||
{
|
||||
bzero(array, sizeof(*array));
|
||||
array->size_of_element= element_size;
|
||||
my_atomic_rwlock_init(&array->lock);
|
||||
}
|
||||
|
||||
static void recursive_free(void **alloc, int level)
|
||||
{
|
||||
if (!alloc)
|
||||
return;
|
||||
|
||||
if (level)
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
|
||||
recursive_free(alloc[i], level-1);
|
||||
my_free(alloc);
|
||||
}
|
||||
else
|
||||
my_free(alloc[-1]);
|
||||
}
|
||||
|
||||
void lf_dynarray_destroy(LF_DYNARRAY *array)
|
||||
{
|
||||
int i;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
|
||||
recursive_free(array->level[i], i);
|
||||
my_atomic_rwlock_destroy(&array->lock);
|
||||
}
|
||||
|
||||
static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]=
|
||||
{
|
||||
0, /* +1 here to to avoid -1's below */
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH +
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH
|
||||
};
|
||||
|
||||
static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]=
|
||||
{
|
||||
0, /* +1 here to to avoid -1's below */
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH,
|
||||
LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
|
||||
LF_DYNARRAY_LEVEL_LENGTH,
|
||||
};
|
||||
|
||||
/*
|
||||
Returns a valid lvalue pointer to the element number 'idx'.
|
||||
Allocates memory if necessary.
|
||||
*/
|
||||
void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx)
|
||||
{
|
||||
void * ptr, * volatile * ptr_ptr= 0;
|
||||
int i;
|
||||
|
||||
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
|
||||
/* no-op */;
|
||||
ptr_ptr= &array->level[i];
|
||||
idx-= dynarray_idxes_in_prev_levels[i];
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
if (!(ptr= *ptr_ptr))
|
||||
{
|
||||
void *alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *),
|
||||
MYF(MY_WME|MY_ZEROFILL));
|
||||
if (unlikely(!alloc))
|
||||
return(NULL);
|
||||
if (my_atomic_casptr(ptr_ptr, &ptr, alloc))
|
||||
ptr= alloc;
|
||||
else
|
||||
my_free(alloc);
|
||||
}
|
||||
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
|
||||
idx%= dynarray_idxes_in_prev_level[i];
|
||||
}
|
||||
if (!(ptr= *ptr_ptr))
|
||||
{
|
||||
uchar *alloc, *data;
|
||||
alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element +
|
||||
max(array->size_of_element, sizeof(void *)),
|
||||
MYF(MY_WME|MY_ZEROFILL));
|
||||
if (unlikely(!alloc))
|
||||
return(NULL);
|
||||
/* reserve the space for free() address */
|
||||
data= alloc + sizeof(void *);
|
||||
{ /* alignment */
|
||||
intptr mod= ((intptr)data) % array->size_of_element;
|
||||
if (mod)
|
||||
data+= array->size_of_element - mod;
|
||||
}
|
||||
((void **)data)[-1]= alloc; /* free() will need the original pointer */
|
||||
if (my_atomic_casptr(ptr_ptr, &ptr, data))
|
||||
ptr= data;
|
||||
else
|
||||
my_free(alloc);
|
||||
}
|
||||
return ((uchar*)ptr) + array->size_of_element * idx;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a pointer to the element number 'idx'
|
||||
or NULL if an element does not exists
|
||||
*/
|
||||
void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx)
|
||||
{
|
||||
void * ptr, * volatile * ptr_ptr= 0;
|
||||
int i;
|
||||
|
||||
for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
|
||||
/* no-op */;
|
||||
ptr_ptr= &array->level[i];
|
||||
idx-= dynarray_idxes_in_prev_levels[i];
|
||||
for (; i > 0; i--)
|
||||
{
|
||||
if (!(ptr= *ptr_ptr))
|
||||
return(NULL);
|
||||
ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
|
||||
idx %= dynarray_idxes_in_prev_level[i];
|
||||
}
|
||||
if (!(ptr= *ptr_ptr))
|
||||
return(NULL);
|
||||
return ((uchar*)ptr) + array->size_of_element * idx;
|
||||
}
|
||||
|
||||
static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level,
|
||||
lf_dynarray_func func, void *arg)
|
||||
{
|
||||
int res, i;
|
||||
if (!ptr)
|
||||
return 0;
|
||||
if (!level)
|
||||
return func(ptr, arg);
|
||||
for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
|
||||
if ((res= recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg)))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calls func(array, arg) on every array of LF_DYNARRAY_LEVEL_LENGTH elements
|
||||
in lf_dynarray.
|
||||
|
||||
DESCRIPTION
|
||||
lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements
|
||||
each. _lf_dynarray_iterate() calls user-supplied function on every array
|
||||
from the set. It is the fastest way to scan the array, faster than
|
||||
for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); }
|
||||
|
||||
NOTE
|
||||
if func() returns non-zero, the scan is aborted
|
||||
*/
|
||||
int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg)
|
||||
{
|
||||
int i, res;
|
||||
for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
|
||||
if ((res= recursive_iterate(array, array->level[i], i, func, arg)))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
extensible hash
|
||||
|
||||
TODO
|
||||
try to get rid of dummy nodes ?
|
||||
for non-unique hash, count only _distinct_ values
|
||||
(but how to do it in lf_hash_delete ?)
|
||||
*/
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_sys.h>
|
||||
#include <my_bit.h>
|
||||
#include <lf.h>
|
||||
|
||||
LF_REQUIRE_PINS(3)
|
||||
|
||||
/* An element of the list */
|
||||
typedef struct {
|
||||
intptr volatile link; /* a pointer to the next element in a listand a flag */
|
||||
uint32 hashnr; /* reversed hash number, for sorting */
|
||||
const uchar *key;
|
||||
size_t keylen;
|
||||
/*
|
||||
data is stored here, directly after the keylen.
|
||||
thus the pointer to data is (void*)(slist_element_ptr+1)
|
||||
*/
|
||||
} LF_SLIST;
|
||||
|
||||
/*
|
||||
a structure to pass the context (pointers two the three successive elements
|
||||
in a list) from lfind to linsert/ldelete
|
||||
*/
|
||||
typedef struct {
|
||||
intptr volatile *prev;
|
||||
LF_SLIST *curr, *next;
|
||||
} CURSOR;
|
||||
|
||||
/*
|
||||
the last bit in LF_SLIST::link is a "deleted" flag.
|
||||
the helper macros below convert it to a pure pointer or a pure flag
|
||||
*/
|
||||
#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
|
||||
#define DELETED(V) ((V) & 1)
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
Search for hashnr/key/keylen in the list starting from 'head' and
|
||||
position the cursor. The list is ORDER BY hashnr, key
|
||||
|
||||
RETURN
|
||||
0 - not found
|
||||
1 - found
|
||||
|
||||
NOTE
|
||||
cursor is positioned in either case
|
||||
pins[0..2] are used, they are NOT removed on return
|
||||
*/
|
||||
static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
||||
const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
|
||||
{
|
||||
uint32 cur_hashnr;
|
||||
const uchar *cur_key;
|
||||
uint cur_keylen;
|
||||
intptr link;
|
||||
|
||||
retry:
|
||||
cursor->prev= (intptr *)head;
|
||||
do { /* PTR() isn't necessary below, head is a dummy node */
|
||||
cursor->curr= (LF_SLIST *)(*cursor->prev);
|
||||
_lf_pin(pins, 1, cursor->curr);
|
||||
} while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
|
||||
for (;;)
|
||||
{
|
||||
if (unlikely(!cursor->curr))
|
||||
return 0; /* end of the list */
|
||||
do {
|
||||
/* QQ: XXX or goto retry ? */
|
||||
link= cursor->curr->link;
|
||||
cursor->next= PTR(link);
|
||||
_lf_pin(pins, 0, cursor->next);
|
||||
} while (link != cursor->curr->link && LF_BACKOFF);
|
||||
cur_hashnr= cursor->curr->hashnr;
|
||||
cur_key= cursor->curr->key;
|
||||
cur_keylen= cursor->curr->keylen;
|
||||
if (*cursor->prev != (intptr)cursor->curr)
|
||||
{
|
||||
(void)LF_BACKOFF;
|
||||
goto retry;
|
||||
}
|
||||
if (!DELETED(link))
|
||||
{
|
||||
if (cur_hashnr >= hashnr)
|
||||
{
|
||||
int r= 1;
|
||||
if (cur_hashnr > hashnr ||
|
||||
(r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key,
|
||||
keylen)) >= 0)
|
||||
return !r;
|
||||
}
|
||||
cursor->prev= &(cursor->curr->link);
|
||||
_lf_pin(pins, 2, cursor->curr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
we found a deleted node - be nice, help the other thread
|
||||
and remove this deleted node
|
||||
*/
|
||||
if (my_atomic_casptr((void **)cursor->prev,
|
||||
(void **)&cursor->curr, cursor->next))
|
||||
_lf_alloc_free(pins, cursor->curr);
|
||||
else
|
||||
{
|
||||
(void)LF_BACKOFF;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
cursor->curr= cursor->next;
|
||||
_lf_pin(pins, 1, cursor->curr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
insert a 'node' in the list that starts from 'head' in the correct
|
||||
position (as found by lfind)
|
||||
|
||||
RETURN
|
||||
0 - inserted
|
||||
not 0 - a pointer to a duplicate (not pinned and thus unusable)
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return all pins are removed.
|
||||
if there're nodes with the same key value, a new node is added before them.
|
||||
*/
|
||||
static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
||||
LF_SLIST *node, LF_PINS *pins, uint flags)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (lfind(head, cs, node->hashnr, node->key, node->keylen,
|
||||
&cursor, pins) &&
|
||||
(flags & LF_HASH_UNIQUE))
|
||||
{
|
||||
res= 0; /* duplicate found */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->link= (intptr)cursor.curr;
|
||||
DBUG_ASSERT(node->link != (intptr)node); /* no circular references */
|
||||
DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */
|
||||
if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
|
||||
{
|
||||
res= 1; /* inserted ok */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
_lf_unpin(pins, 2);
|
||||
/*
|
||||
Note that cursor.curr is not pinned here and the pointer is unreliable,
|
||||
the object may dissapear anytime. But if it points to a dummy node, the
|
||||
pointer is safe, because dummy nodes are never freed - initialize_bucket()
|
||||
uses this fact.
|
||||
*/
|
||||
return res ? 0 : cursor.curr;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
deletes a node as identified by hashnr/keey/keylen from the list
|
||||
that starts from 'head'
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - not found
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return all pins are removed.
|
||||
*/
|
||||
static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
||||
const uchar *key, uint keylen, LF_PINS *pins)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins))
|
||||
{
|
||||
res= 1; /* not found */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mark the node deleted */
|
||||
if (my_atomic_casptr((void **)&(cursor.curr->link),
|
||||
(void **)&cursor.next,
|
||||
(void *)(((intptr)cursor.next) | 1)))
|
||||
{
|
||||
/* and remove it from the list */
|
||||
if (my_atomic_casptr((void **)cursor.prev,
|
||||
(void **)&cursor.curr, cursor.next))
|
||||
_lf_alloc_free(pins, cursor.curr);
|
||||
else
|
||||
{
|
||||
/*
|
||||
somebody already "helped" us and removed the node ?
|
||||
Let's check if we need to help that someone too!
|
||||
(to ensure the number of "set DELETED flag" actions
|
||||
is equal to the number of "remove from the list" actions)
|
||||
*/
|
||||
lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
||||
}
|
||||
res= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
_lf_unpin(pins, 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
searches for a node as identified by hashnr/keey/keylen in the list
|
||||
that starts from 'head'
|
||||
|
||||
RETURN
|
||||
0 - not found
|
||||
node - found
|
||||
|
||||
NOTE
|
||||
it uses pins[0..2], on return the pin[2] keeps the node found
|
||||
all other pins are removed.
|
||||
*/
|
||||
static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
||||
uint32 hashnr, const uchar *key, uint keylen,
|
||||
LF_PINS *pins)
|
||||
{
|
||||
CURSOR cursor;
|
||||
int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
||||
if (res)
|
||||
_lf_pin(pins, 2, cursor.curr);
|
||||
_lf_unpin(pins, 0);
|
||||
_lf_unpin(pins, 1);
|
||||
return res ? cursor.curr : 0;
|
||||
}
|
||||
|
||||
static inline const uchar* hash_key(const LF_HASH *hash,
|
||||
const uchar *record, size_t *length)
|
||||
{
|
||||
if (hash->get_key)
|
||||
return (*hash->get_key)(record, length, 0);
|
||||
*length= hash->key_length;
|
||||
return record + hash->key_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
Compute the hash key value from the raw key.
|
||||
|
||||
@note, that the hash value is limited to 2^31, because we need one
|
||||
bit to distinguish between normal and dummy nodes.
|
||||
*/
|
||||
static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen)
|
||||
{
|
||||
ulong nr1= 1, nr2= 4;
|
||||
hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen,
|
||||
&nr1, &nr2);
|
||||
return nr1 & INT_MAX32;
|
||||
}
|
||||
|
||||
#define MAX_LOAD 1.0 /* average number of elements in a bucket */
|
||||
|
||||
static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
|
||||
|
||||
/*
|
||||
Initializes lf_hash, the arguments are compatible with hash_init
|
||||
|
||||
@note element_size sets both the size of allocated memory block for
|
||||
lf_alloc and a size of memcpy'ed block size in lf_hash_insert. Typically
|
||||
they are the same, indeed. But LF_HASH::element_size can be decreased
|
||||
after lf_hash_init, and then lf_alloc will allocate larger block that
|
||||
lf_hash_insert will copy over. It is desireable if part of the element
|
||||
is expensive to initialize - for example if there is a mutex or
|
||||
DYNAMIC_ARRAY. In this case they should be initialize in the
|
||||
LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them.
|
||||
See wt_init() for example.
|
||||
*/
|
||||
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
|
||||
uint key_offset, uint key_length, my_hash_get_key get_key,
|
||||
CHARSET_INFO *charset)
|
||||
{
|
||||
lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size,
|
||||
offsetof(LF_SLIST, key));
|
||||
lf_dynarray_init(&hash->array, sizeof(LF_SLIST *));
|
||||
hash->size= 1;
|
||||
hash->count= 0;
|
||||
hash->element_size= element_size;
|
||||
hash->flags= flags;
|
||||
hash->charset= charset ? charset : &my_charset_bin;
|
||||
hash->key_offset= key_offset;
|
||||
hash->key_length= key_length;
|
||||
hash->get_key= get_key;
|
||||
DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
|
||||
}
|
||||
|
||||
void lf_hash_destroy(LF_HASH *hash)
|
||||
{
|
||||
LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0);
|
||||
|
||||
if (unlikely(!head))
|
||||
return;
|
||||
el= *head;
|
||||
|
||||
while (el)
|
||||
{
|
||||
intptr next= el->link;
|
||||
if (el->hashnr & 1)
|
||||
lf_alloc_direct_free(&hash->alloc, el); /* normal node */
|
||||
else
|
||||
my_free(el); /* dummy node */
|
||||
el= (LF_SLIST *)next;
|
||||
}
|
||||
lf_alloc_destroy(&hash->alloc);
|
||||
lf_dynarray_destroy(&hash->array);
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
inserts a new element to a hash. it will have a _copy_ of
|
||||
data, not a pointer to it.
|
||||
|
||||
RETURN
|
||||
0 - inserted
|
||||
1 - didn't (unique key conflict)
|
||||
-1 - out of memory
|
||||
|
||||
NOTE
|
||||
see linsert() for pin usage notes
|
||||
*/
|
||||
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
|
||||
{
|
||||
int csize, bucket, hashnr;
|
||||
LF_SLIST *node, * volatile *el;
|
||||
|
||||
lf_rwlock_by_pins(pins);
|
||||
node= (LF_SLIST *)_lf_alloc_new(pins);
|
||||
if (unlikely(!node))
|
||||
return -1;
|
||||
memcpy(node+1, data, hash->element_size);
|
||||
node->key= hash_key(hash, (uchar *)(node+1), &node->keylen);
|
||||
hashnr= calc_hash(hash, node->key, node->keylen);
|
||||
bucket= hashnr % hash->size;
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return -1;
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return -1;
|
||||
node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */
|
||||
if (linsert(el, hash->charset, node, pins, hash->flags))
|
||||
{
|
||||
_lf_alloc_free(pins, node);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 1;
|
||||
}
|
||||
csize= hash->size;
|
||||
if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
|
||||
my_atomic_cas32(&hash->size, &csize, csize*2);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
deletes an element with the given key from the hash (if a hash is
|
||||
not unique and there're many elements with this key - the "first"
|
||||
matching element is deleted)
|
||||
RETURN
|
||||
0 - deleted
|
||||
1 - didn't (not found)
|
||||
-1 - out of memory
|
||||
NOTE
|
||||
see ldelete() for pin usage notes
|
||||
*/
|
||||
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
{
|
||||
LF_SLIST * volatile *el;
|
||||
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
|
||||
|
||||
bucket= hashnr % hash->size;
|
||||
lf_rwlock_by_pins(pins);
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return -1;
|
||||
/*
|
||||
note that we still need to initialize_bucket here,
|
||||
we cannot return "node not found", because an old bucket of that
|
||||
node may've been split and the node was assigned to a new bucket
|
||||
that was never accessed before and thus is not initialized.
|
||||
*/
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return -1;
|
||||
if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
||||
(uchar *)key, keylen, pins))
|
||||
{
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 1;
|
||||
}
|
||||
my_atomic_add32(&hash->count, -1);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
RETURN
|
||||
a pointer to an element with the given key (if a hash is not unique and
|
||||
there're many elements with this key - the "first" matching element)
|
||||
NULL if nothing is found
|
||||
MY_ERRPTR if OOM
|
||||
|
||||
NOTE
|
||||
see lsearch() for pin usage notes
|
||||
*/
|
||||
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
{
|
||||
LF_SLIST * volatile *el, *found;
|
||||
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
|
||||
|
||||
bucket= hashnr % hash->size;
|
||||
lf_rwlock_by_pins(pins);
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
return MY_ERRPTR;
|
||||
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
|
||||
return MY_ERRPTR;
|
||||
found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
||||
(uchar *)key, keylen, pins);
|
||||
lf_rwunlock_by_pins(pins);
|
||||
return found ? found+1 : 0;
|
||||
}
|
||||
|
||||
static const uchar *dummy_key= (uchar*)"";
|
||||
|
||||
/*
|
||||
RETURN
|
||||
0 - ok
|
||||
-1 - out of memory
|
||||
*/
|
||||
static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
|
||||
uint bucket, LF_PINS *pins)
|
||||
{
|
||||
uint parent= my_clear_highest_bit(bucket);
|
||||
LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
|
||||
LF_SLIST **tmp= 0, *cur;
|
||||
LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
|
||||
if (unlikely(!el || !dummy))
|
||||
return -1;
|
||||
if (*el == NULL && bucket &&
|
||||
unlikely(initialize_bucket(hash, el, parent, pins)))
|
||||
return -1;
|
||||
dummy->hashnr= my_reverse_bits(bucket) | 0; /* dummy node */
|
||||
dummy->key= dummy_key;
|
||||
dummy->keylen= 0;
|
||||
if ((cur= linsert(el, hash->charset, dummy, pins, LF_HASH_UNIQUE)))
|
||||
{
|
||||
my_free(dummy);
|
||||
dummy= cur;
|
||||
}
|
||||
my_atomic_casptr((void **)node, (void **)&tmp, dummy);
|
||||
/*
|
||||
note that if the CAS above failed (after linsert() succeeded),
|
||||
it would mean that some other thread has executed linsert() for
|
||||
the same dummy node, its linsert() failed, it picked up our
|
||||
dummy node (in "dummy= cur") and executed the same CAS as above.
|
||||
Which means that even if CAS above failed we don't need to retry,
|
||||
and we should not free(dummy) - there's no memory leak here
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
@@ -61,8 +61,8 @@ void list_free(LIST *root, uint free_data)
|
||||
{
|
||||
next=root->next;
|
||||
if (free_data)
|
||||
my_free((uchar*) root->data,MYF(0));
|
||||
my_free((uchar*) root,MYF(0));
|
||||
my_free(root->data);
|
||||
my_free(root);
|
||||
root=next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
|
||||
not require an integer type which is exactly 32 bits. This work
|
||||
draws on the changes for the same purpose by Tatu Ylonen
|
||||
<[email protected]> as part of SSH, but since I didn't actually use
|
||||
that code, there is no copyright issue. I hereby disclaim
|
||||
copyright in any changes I have made; this code remains in the
|
||||
public domain. */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include "my_md5.h"
|
||||
|
||||
#include <string.h> /* for memcpy() and memset() */
|
||||
|
||||
|
||||
static void
|
||||
my_MD5Transform (cvs_uint32 buf[4], const unsigned char in[64]);
|
||||
|
||||
/* Little-endian byte-swapping routines. Note that these do not
|
||||
depend on the size of datatypes such as uint32, nor do they require
|
||||
us to detect the endianness of the machine we are running on. It
|
||||
is possible they should be macros for speed, but I would be
|
||||
surprised if they were a performance bottleneck for MD5. */
|
||||
|
||||
static uint32 getu32 (const unsigned char *addr)
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
|
||||
| addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
static void
|
||||
putu32 (uint32 data, unsigned char *addr)
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
initialization constants.
|
||||
*/
|
||||
void
|
||||
my_MD5Init (my_MD5Context *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Update context to reflect the concatenation of another buffer full
|
||||
of bytes.
|
||||
*/
|
||||
void
|
||||
my_MD5Update (my_MD5Context *ctx, unsigned char const *buf, unsigned len)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void
|
||||
my_MD5Final (unsigned char digest[16], my_MD5Context *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
putu32(ctx->bits[0], ctx->in + 56);
|
||||
putu32(ctx->bits[1], ctx->in + 60);
|
||||
|
||||
my_MD5Transform (ctx->buf, ctx->in);
|
||||
putu32(ctx->buf[0], digest);
|
||||
putu32(ctx->buf[1], digest + 4);
|
||||
putu32(ctx->buf[2], digest + 8);
|
||||
putu32(ctx->buf[3], digest + 12);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void
|
||||
my_MD5Transform (uint32 buf[4], const unsigned char inraw[64])
|
||||
{
|
||||
register uint32 a, b, c, d;
|
||||
uint32 in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
/*
|
||||
Simple test program. Can use it to manually run the tests from
|
||||
RFC1321 for example.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
my_MD5Context context;
|
||||
unsigned char checksum[16];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
for (j = 1; j < argc; ++j)
|
||||
{
|
||||
printf ("MD5 (\"%s\") = ", argv[j]);
|
||||
my_MD5Init (&context);
|
||||
my_MD5Update (&context, argv[j], strlen (argv[j]));
|
||||
my_MD5Final (checksum, &context);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
@@ -71,8 +71,8 @@ my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
|
||||
{
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
my_free(cache->dir, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(cache->prefix,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(cache->dir);
|
||||
my_free(cache->prefix);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@@ -110,12 +110,12 @@ void close_cached_file(IO_CACHE *cache)
|
||||
if (cache->file_name)
|
||||
{
|
||||
(void) my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT));
|
||||
my_free(cache->file_name,MYF(0));
|
||||
my_free(cache->file_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
my_free(cache->dir,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(cache->prefix,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(cache->dir);
|
||||
my_free(cache->prefix);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,7 @@ size_t dirname_length(const char *name)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (*pos == FN_LIBCHAR || *pos == '/'
|
||||
#ifdef FN_C_AFTER_DIR
|
||||
|| *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
|
||||
#endif
|
||||
)
|
||||
if (*pos == FN_LIBCHAR || *pos == '/')
|
||||
gpos=pos;
|
||||
}
|
||||
return (size_t) (gpos+1-(char*) name);
|
||||
@@ -88,8 +84,7 @@ size_t dirname_part(char *to, const char *name, size_t *to_res_length)
|
||||
from_end Pointer at end of filename (normally end \0)
|
||||
|
||||
IMPLEMENTATION
|
||||
If MSDOS converts '/' to '\'
|
||||
If VMS converts '<' to '[' and '>' to ']'
|
||||
If Windows converts '/' to '\'
|
||||
Adds a FN_LIBCHAR to end if the result string if there isn't one
|
||||
and the last isn't dev_char.
|
||||
Copies data from 'from' until ASCII(0) for until from == from_end
|
||||
@@ -118,18 +113,12 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
|
||||
if (!from_end || (from_end - from) > FN_REFLEN-2)
|
||||
from_end=from+FN_REFLEN -2;
|
||||
|
||||
#if FN_LIBCHAR != '/' || defined(FN_C_BEFORE_DIR_2)
|
||||
#if FN_LIBCHAR != '/'
|
||||
{
|
||||
for (; from != from_end && *from ; from++)
|
||||
{
|
||||
if (*from == '/')
|
||||
*to++= FN_LIBCHAR;
|
||||
#ifdef FN_C_BEFORE_DIR_2
|
||||
else if (*from == FN_C_BEFORE_DIR_2)
|
||||
*to++= FN_C_BEFORE_DIR;
|
||||
else if (*from == FN_C_AFTER_DIR_2)
|
||||
*to++= FN_C_AFTER_DIR;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
#ifdef BACKSLASH_MBTAIL
|
||||
|
||||
@@ -39,7 +39,7 @@ char *fn_ext(const char *name)
|
||||
DBUG_ENTER("fn_ext");
|
||||
DBUG_PRINT("mfunkt",("name: '%s'",name));
|
||||
|
||||
#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR) || defined(BASKSLASH_MBTAIL)
|
||||
#if defined(FN_DEVCHAR) || defined(BASKSLASH_MBTAIL)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
size_t res_length;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Get date in a printable form: yyyy-mm-dd hh:mm:ss */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
get date as string
|
||||
|
||||
SYNOPSIS
|
||||
get_date()
|
||||
to - string where date will be written
|
||||
flag - format of date:
|
||||
If flag & GETDATE_TIME Return date and time
|
||||
If flag & GETDATE_SHORT_DATE Return short date format YYMMDD
|
||||
If flag & GETDATE_HHMMSSTIME Return time in HHMMDD format.
|
||||
If flag & GETDATE_GMT Date/time in GMT
|
||||
If flag & GETDATE_FIXEDLENGTH Return fixed length date/time
|
||||
date - for conversion
|
||||
*/
|
||||
|
||||
|
||||
void get_date(register char * to, int flag, time_t date)
|
||||
{
|
||||
reg2 struct tm *start_time;
|
||||
time_t skr;
|
||||
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
|
||||
struct tm tm_tmp;
|
||||
#endif
|
||||
|
||||
skr=date ? (time_t) date : my_time(0);
|
||||
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
|
||||
if (flag & GETDATE_GMT)
|
||||
gmtime_r(&skr,&tm_tmp);
|
||||
else
|
||||
localtime_r(&skr,&tm_tmp);
|
||||
start_time= &tm_tmp;
|
||||
#else
|
||||
if (flag & GETDATE_GMT)
|
||||
start_time= gmtime(&skr);
|
||||
else
|
||||
start_time= localtime(&skr);
|
||||
#endif
|
||||
if (flag & GETDATE_SHORT_DATE)
|
||||
sprintf(to,"%02d%02d%02d",
|
||||
start_time->tm_year % 100,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
else
|
||||
sprintf(to, ((flag & GETDATE_FIXEDLENGTH) ?
|
||||
"%4d-%02d-%02d" : "%d-%02d-%02d"),
|
||||
start_time->tm_year+1900,
|
||||
start_time->tm_mon+1,
|
||||
start_time->tm_mday);
|
||||
if (flag & GETDATE_DATE_TIME)
|
||||
sprintf(strend(to),
|
||||
((flag & GETDATE_FIXEDLENGTH) ?
|
||||
" %02d:%02d:%02d" : " %2d:%02d:%02d"),
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
start_time->tm_sec);
|
||||
else if (flag & GETDATE_HHMMSSTIME)
|
||||
sprintf(strend(to),"%02d%02d%02d",
|
||||
start_time->tm_hour,
|
||||
start_time->tm_min,
|
||||
start_time->tm_sec);
|
||||
} /* get_date */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -47,7 +47,6 @@ TODO:
|
||||
write buffer to the read buffer before we start to reuse it.
|
||||
*/
|
||||
|
||||
#define MAP_TO_USE_RAID
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#ifdef HAVE_AIOWAIT
|
||||
@@ -56,15 +55,10 @@ static void my_aiowait(my_aio_result *result);
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef THREAD
|
||||
#define lock_append_buffer(info) \
|
||||
pthread_mutex_lock(&(info)->append_buffer_lock)
|
||||
mysql_mutex_lock(&(info)->append_buffer_lock)
|
||||
#define unlock_append_buffer(info) \
|
||||
pthread_mutex_unlock(&(info)->append_buffer_lock)
|
||||
#else
|
||||
#define lock_append_buffer(info)
|
||||
#define unlock_append_buffer(info)
|
||||
#endif
|
||||
mysql_mutex_unlock(&(info)->append_buffer_lock)
|
||||
|
||||
#define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1))
|
||||
#define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1))
|
||||
@@ -117,11 +111,7 @@ init_functions(IO_CACHE* info)
|
||||
info->write_function = 0; /* Force a core if used */
|
||||
break;
|
||||
default:
|
||||
info->read_function =
|
||||
#ifdef THREAD
|
||||
info->share ? _my_b_read_r :
|
||||
#endif
|
||||
_my_b_read;
|
||||
info->read_function = info->share ? _my_b_read_r : _my_b_read;
|
||||
info->write_function = _my_b_write;
|
||||
}
|
||||
|
||||
@@ -174,7 +164,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
|
||||
|
||||
if (file >= 0)
|
||||
{
|
||||
pos= my_tell(file, MYF(0));
|
||||
pos= mysql_file_tell(file, MYF(0));
|
||||
if ((pos == (my_off_t) -1) && (my_errno == ESPIPE))
|
||||
{
|
||||
/*
|
||||
@@ -194,9 +184,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
|
||||
}
|
||||
|
||||
info->disk_writes= 0;
|
||||
#ifdef THREAD
|
||||
info->share=0;
|
||||
#endif
|
||||
|
||||
if (!cachesize && !(cachesize= my_default_record_cache_size))
|
||||
DBUG_RETURN(1); /* No cache requested */
|
||||
@@ -206,7 +194,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
|
||||
if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
|
||||
{
|
||||
/* Calculate end of file to avoid allocating oversized buffers */
|
||||
end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0));
|
||||
end_of_file= mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
|
||||
/* Need to reset seek_not_done now that we just did a seek. */
|
||||
info->seek_not_done= end_of_file == seek_offset ? 0 : 1;
|
||||
if (end_of_file < seek_offset)
|
||||
@@ -264,11 +252,10 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
|
||||
{
|
||||
info->append_read_pos = info->write_pos = info->write_buffer;
|
||||
info->write_end = info->write_buffer + info->buffer_length;
|
||||
#ifdef THREAD
|
||||
pthread_mutex_init(&info->append_buffer_lock,MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
mysql_mutex_init(key_IO_CACHE_append_buffer_lock,
|
||||
&info->append_buffer_lock, MY_MUTEX_INIT_FAST);
|
||||
}
|
||||
#if defined(SAFE_MUTEX) && defined(THREAD)
|
||||
#if defined(SAFE_MUTEX)
|
||||
else
|
||||
{
|
||||
/* Clear mutex so that safe_mutex will notice that it's not initialized */
|
||||
@@ -454,7 +441,9 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
|
||||
|
||||
RETURN
|
||||
0 we succeeded in reading all data
|
||||
1 Error: can't read requested characters
|
||||
1 Error: couldn't read requested characters. In this case:
|
||||
If info->error == -1, we got a read error.
|
||||
Otherwise info->error contains the number of bytes in Buffer.
|
||||
*/
|
||||
|
||||
int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
@@ -463,6 +452,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
my_off_t pos_in_file;
|
||||
DBUG_ENTER("_my_b_read");
|
||||
|
||||
/* If the buffer is not empty yet, copy what is available. */
|
||||
if ((left_length= (size_t) (info->read_end-info->read_pos)))
|
||||
{
|
||||
DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
|
||||
@@ -474,7 +464,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
/* pos_in_file always point on where info->buffer was read */
|
||||
pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
|
||||
|
||||
/*
|
||||
/*
|
||||
Whenever a function which operates on IO_CACHE flushes/writes
|
||||
some part of the IO_CACHE to disk it will set the property
|
||||
"seek_not_done" to indicate this to other functions operating
|
||||
@@ -482,7 +472,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
*/
|
||||
if (info->seek_not_done)
|
||||
{
|
||||
if ((my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))
|
||||
if ((mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0))
|
||||
!= MY_FILEPOS_ERROR))
|
||||
{
|
||||
/* No error, reset seek_not_done flag. */
|
||||
@@ -501,19 +491,38 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate, how much we are within a IO_SIZE block. Ideally this
|
||||
should be zero.
|
||||
*/
|
||||
diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
|
||||
|
||||
/*
|
||||
If more than a block plus the rest of the current block is wanted,
|
||||
we do read directly, without filling the buffer.
|
||||
*/
|
||||
if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
|
||||
{ /* Fill first intern buffer */
|
||||
size_t read_length;
|
||||
if (info->end_of_file <= pos_in_file)
|
||||
{ /* End of file */
|
||||
{
|
||||
/* End of file. Return, what we did copy from the buffer. */
|
||||
info->error= (int) left_length;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
/*
|
||||
Crop the wanted count to a multiple of IO_SIZE and subtract,
|
||||
what we did already read from a block. That way, the read will
|
||||
end aligned with a block.
|
||||
*/
|
||||
length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
|
||||
if ((read_length= my_read(info->file,Buffer, length, info->myflags))
|
||||
if ((read_length= mysql_file_read(info->file,Buffer, length, info->myflags))
|
||||
!= length)
|
||||
{
|
||||
/*
|
||||
If we didn't get, what we wanted, we either return -1 for a read
|
||||
error, or (it's end of file), how much we got in total.
|
||||
*/
|
||||
info->error= (read_length == (size_t) -1 ? -1 :
|
||||
(int) (read_length+left_length));
|
||||
DBUG_RETURN(1);
|
||||
@@ -525,30 +534,52 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
diff_length=0;
|
||||
}
|
||||
|
||||
/*
|
||||
At this point, we want less than one and a partial block.
|
||||
We will read a full cache, minus the number of bytes, we are
|
||||
within a block already. So we will reach new alignment.
|
||||
*/
|
||||
max_length= info->read_length-diff_length;
|
||||
/* We will not read past end of file. */
|
||||
if (info->type != READ_FIFO &&
|
||||
max_length > (info->end_of_file - pos_in_file))
|
||||
max_length= (size_t) (info->end_of_file - pos_in_file);
|
||||
/*
|
||||
If there is nothing left to read,
|
||||
we either are done, or we failed to fulfill the request.
|
||||
Otherwise, we read max_length into the cache.
|
||||
*/
|
||||
if (!max_length)
|
||||
{
|
||||
if (Count)
|
||||
{
|
||||
info->error= left_length; /* We only got this many char */
|
||||
/* We couldn't fulfil the request. Return, how much we got. */
|
||||
info->error= left_length;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
length=0; /* Didn't read any chars */
|
||||
}
|
||||
else if ((length= my_read(info->file,info->buffer, max_length,
|
||||
else if ((length= mysql_file_read(info->file,info->buffer, max_length,
|
||||
info->myflags)) < Count ||
|
||||
length == (size_t) -1)
|
||||
{
|
||||
/*
|
||||
We got an read error, or less than requested (end of file).
|
||||
If not a read error, copy, what we got.
|
||||
*/
|
||||
if (length != (size_t) -1)
|
||||
memcpy(Buffer, info->buffer, length);
|
||||
info->pos_in_file= pos_in_file;
|
||||
/* For a read error, return -1, otherwise, what we got in total. */
|
||||
info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
|
||||
info->read_pos=info->read_end=info->buffer;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
/*
|
||||
Count is the remaining number of bytes requested.
|
||||
length is the amount of data in the cache.
|
||||
Read Count bytes from the cache.
|
||||
*/
|
||||
info->read_pos=info->buffer+Count;
|
||||
info->read_end=info->buffer+length;
|
||||
info->pos_in_file=pos_in_file;
|
||||
@@ -557,7 +588,6 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
}
|
||||
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Prepare IO_CACHE for shared use.
|
||||
|
||||
@@ -639,9 +669,10 @@ void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
|
||||
DBUG_ASSERT(read_cache->type == READ_CACHE);
|
||||
DBUG_ASSERT(!write_cache || (write_cache->type == WRITE_CACHE));
|
||||
|
||||
pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&cshare->cond, 0);
|
||||
pthread_cond_init(&cshare->cond_writer, 0);
|
||||
mysql_mutex_init(key_IO_CACHE_SHARE_mutex,
|
||||
&cshare->mutex, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_IO_CACHE_SHARE_cond, &cshare->cond, 0);
|
||||
mysql_cond_init(key_IO_CACHE_SHARE_cond_writer, &cshare->cond_writer, 0);
|
||||
|
||||
cshare->running_threads= num_threads;
|
||||
cshare->total_threads= num_threads;
|
||||
@@ -692,7 +723,7 @@ void remove_io_thread(IO_CACHE *cache)
|
||||
if (cache == cshare->source_cache)
|
||||
flush_io_cache(cache);
|
||||
|
||||
pthread_mutex_lock(&cshare->mutex);
|
||||
mysql_mutex_lock(&cshare->mutex);
|
||||
DBUG_PRINT("io_cache_share", ("%s: 0x%lx",
|
||||
(cache == cshare->source_cache) ?
|
||||
"writer" : "reader", (long) cache));
|
||||
@@ -715,18 +746,18 @@ void remove_io_thread(IO_CACHE *cache)
|
||||
if (!--cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("the last running thread leaves, wake all"));
|
||||
pthread_cond_signal(&cshare->cond_writer);
|
||||
pthread_cond_broadcast(&cshare->cond);
|
||||
mysql_cond_signal(&cshare->cond_writer);
|
||||
mysql_cond_broadcast(&cshare->cond);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
mysql_mutex_unlock(&cshare->mutex);
|
||||
|
||||
if (!total)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("last thread removed, destroy share"));
|
||||
pthread_cond_destroy (&cshare->cond_writer);
|
||||
pthread_cond_destroy (&cshare->cond);
|
||||
pthread_mutex_destroy(&cshare->mutex);
|
||||
mysql_cond_destroy (&cshare->cond_writer);
|
||||
mysql_cond_destroy (&cshare->cond);
|
||||
mysql_mutex_destroy(&cshare->mutex);
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -767,7 +798,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
DBUG_ENTER("lock_io_cache");
|
||||
|
||||
/* Enter the lock. */
|
||||
pthread_mutex_lock(&cshare->mutex);
|
||||
mysql_mutex_lock(&cshare->mutex);
|
||||
cshare->running_threads--;
|
||||
DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u",
|
||||
(cache == cshare->source_cache) ?
|
||||
@@ -784,7 +815,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
while (cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("writer waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond_writer, &cshare->mutex);
|
||||
mysql_cond_wait(&cshare->cond_writer, &cshare->mutex);
|
||||
}
|
||||
DBUG_PRINT("io_cache_share", ("writer awoke, going to copy"));
|
||||
|
||||
@@ -796,7 +827,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
if (!cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("waking writer"));
|
||||
pthread_cond_signal(&cshare->cond_writer);
|
||||
mysql_cond_signal(&cshare->cond_writer);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -808,7 +839,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
cshare->source_cache)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
mysql_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -850,7 +881,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
cshare->running_threads)
|
||||
{
|
||||
DBUG_PRINT("io_cache_share", ("reader waits in lock"));
|
||||
pthread_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
mysql_cond_wait(&cshare->cond, &cshare->mutex);
|
||||
}
|
||||
|
||||
/* If the block is not yet read, continue with a locked cache and read. */
|
||||
@@ -872,7 +903,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
|
||||
Leave the lock. Do not call unlock_io_cache() later. The thread that
|
||||
filled the buffer did this and marked all threads as running.
|
||||
*/
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
mysql_mutex_unlock(&cshare->mutex);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@@ -915,8 +946,8 @@ static void unlock_io_cache(IO_CACHE *cache)
|
||||
cshare->total_threads));
|
||||
|
||||
cshare->running_threads= cshare->total_threads;
|
||||
pthread_cond_broadcast(&cshare->cond);
|
||||
pthread_mutex_unlock(&cshare->mutex);
|
||||
mysql_cond_broadcast(&cshare->cond);
|
||||
mysql_mutex_unlock(&cshare->mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -1011,7 +1042,7 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
|
||||
*/
|
||||
if (cache->seek_not_done)
|
||||
{
|
||||
if (my_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0))
|
||||
if (mysql_file_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0))
|
||||
== MY_FILEPOS_ERROR)
|
||||
{
|
||||
cache->error= -1;
|
||||
@@ -1019,7 +1050,7 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
len= my_read(cache->file, cache->buffer, length, cache->myflags);
|
||||
len= mysql_file_read(cache->file, cache->buffer, length, cache->myflags);
|
||||
}
|
||||
DBUG_PRINT("io_cache_share", ("read %lu bytes", (ulong) len));
|
||||
|
||||
@@ -1117,7 +1148,6 @@ static void copy_to_read_buffer(IO_CACHE *write_cache,
|
||||
write_length-= copy_length;
|
||||
}
|
||||
}
|
||||
#endif /*THREAD*/
|
||||
|
||||
|
||||
/*
|
||||
@@ -1158,7 +1188,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
With read-append cache we must always do a seek before we read,
|
||||
because the write could have moved the file pointer astray
|
||||
*/
|
||||
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) == MY_FILEPOS_ERROR)
|
||||
if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
|
||||
{
|
||||
info->error= -1;
|
||||
unlock_append_buffer(info);
|
||||
@@ -1175,8 +1205,8 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
size_t read_length;
|
||||
|
||||
length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
|
||||
if ((read_length= my_read(info->file,Buffer, length,
|
||||
info->myflags)) == (size_t) -1)
|
||||
if ((read_length= mysql_file_read(info->file,Buffer, length,
|
||||
info->myflags)) == (size_t) -1)
|
||||
{
|
||||
info->error= -1;
|
||||
unlock_append_buffer(info);
|
||||
@@ -1209,7 +1239,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
}
|
||||
else
|
||||
{
|
||||
length= my_read(info->file,info->buffer, max_length, info->myflags);
|
||||
length= mysql_file_read(info->file,info->buffer, max_length, info->myflags);
|
||||
if (length == (size_t) -1)
|
||||
{
|
||||
info->error= -1;
|
||||
@@ -1386,7 +1416,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))
|
||||
if (mysql_file_seek(info->file, next_pos_in_file, MY_SEEK_SET, MYF(0))
|
||||
== MY_FILEPOS_ERROR)
|
||||
{
|
||||
info->error= -1;
|
||||
@@ -1396,8 +1426,8 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
read_length=IO_SIZE*2- (size_t) (next_pos_in_file & (IO_SIZE-1));
|
||||
if (Count < read_length)
|
||||
{ /* Small block, read to cache */
|
||||
if ((read_length=my_read(info->file,info->request_pos,
|
||||
read_length, info->myflags)) == (size_t) -1)
|
||||
if ((read_length=mysql_file_read(info->file,info->request_pos,
|
||||
read_length, info->myflags)) == (size_t) -1)
|
||||
return info->error= -1;
|
||||
use_length=min(Count,read_length);
|
||||
memcpy(Buffer,info->request_pos,(size_t) use_length);
|
||||
@@ -1417,7 +1447,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
|
||||
}
|
||||
else
|
||||
{ /* Big block, don't cache it */
|
||||
if ((read_length= my_read(info->file,Buffer, Count,info->myflags))
|
||||
if ((read_length= mysql_file_read(info->file, Buffer, Count,info->myflags))
|
||||
!= Count)
|
||||
{
|
||||
info->error= read_length == (size_t) -1 ? -1 : read_length+left_length;
|
||||
@@ -1524,17 +1554,16 @@ int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
|
||||
"seek_not_done" to indicate this to other functions operating
|
||||
on the IO_CACHE.
|
||||
*/
|
||||
if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)))
|
||||
if (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET, MYF(0)))
|
||||
{
|
||||
info->error= -1;
|
||||
return (1);
|
||||
}
|
||||
info->seek_not_done=0;
|
||||
}
|
||||
if (my_write(info->file, Buffer, length, info->myflags | MY_NABP))
|
||||
if (mysql_file_write(info->file, Buffer, length, info->myflags | MY_NABP))
|
||||
return info->error= -1;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
In case of a shared I/O cache with a writer we normally do direct
|
||||
write cache to read cache copy. Simulate this here by direct
|
||||
@@ -1548,7 +1577,6 @@ int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
|
||||
*/
|
||||
if (info->share)
|
||||
copy_to_read_buffer(info, Buffer, length);
|
||||
#endif
|
||||
|
||||
Count-=length;
|
||||
Buffer+=length;
|
||||
@@ -1570,13 +1598,11 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
|
||||
{
|
||||
size_t rest_length,length;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Assert that we cannot come here with a shared cache. If we do one
|
||||
day, we might need to add a call to copy_to_read_buffer().
|
||||
*/
|
||||
DBUG_ASSERT(!info->share);
|
||||
#endif
|
||||
|
||||
lock_append_buffer(info);
|
||||
rest_length= (size_t) (info->write_end - info->write_pos);
|
||||
@@ -1594,7 +1620,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
|
||||
if (Count >= IO_SIZE)
|
||||
{ /* Fill first intern buffer */
|
||||
length=Count & (size_t) ~(IO_SIZE-1);
|
||||
if (my_write(info->file,Buffer, length, info->myflags | MY_NABP))
|
||||
if (mysql_file_write(info->file,Buffer, length, info->myflags | MY_NABP))
|
||||
{
|
||||
unlock_append_buffer(info);
|
||||
return info->error= -1;
|
||||
@@ -1638,23 +1664,21 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
|
||||
size_t length;
|
||||
int error=0;
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Assert that we cannot come here with a shared cache. If we do one
|
||||
day, we might need to add a call to copy_to_read_buffer().
|
||||
*/
|
||||
DBUG_ASSERT(!info->share);
|
||||
#endif
|
||||
|
||||
if (pos < info->pos_in_file)
|
||||
{
|
||||
/* Of no overlap, write everything without buffering */
|
||||
if (pos + Count <= info->pos_in_file)
|
||||
return my_pwrite(info->file, Buffer, Count, pos,
|
||||
info->myflags | MY_NABP);
|
||||
return mysql_file_pwrite(info->file, Buffer, Count, pos,
|
||||
info->myflags | MY_NABP);
|
||||
/* Write the part of the block that is before buffer */
|
||||
length= (uint) (info->pos_in_file - pos);
|
||||
if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
|
||||
if (mysql_file_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
|
||||
info->error= error= -1;
|
||||
Buffer+=length;
|
||||
pos+= length;
|
||||
@@ -1690,16 +1714,10 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
|
||||
|
||||
/* Flush write cache */
|
||||
|
||||
#ifdef THREAD
|
||||
#define LOCK_APPEND_BUFFER if (need_append_buffer_lock) \
|
||||
lock_append_buffer(info);
|
||||
#define UNLOCK_APPEND_BUFFER if (need_append_buffer_lock) \
|
||||
unlock_append_buffer(info);
|
||||
#else
|
||||
#define LOCK_APPEND_BUFFER
|
||||
#define UNLOCK_APPEND_BUFFER
|
||||
#endif
|
||||
|
||||
|
||||
int my_b_flush_io_cache(IO_CACHE *info,
|
||||
int need_append_buffer_lock __attribute__((unused)))
|
||||
@@ -1710,10 +1728,8 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
DBUG_ENTER("my_b_flush_io_cache");
|
||||
DBUG_PRINT("enter", ("cache: 0x%lx", (long) info));
|
||||
|
||||
#ifdef THREAD
|
||||
if (!append_cache)
|
||||
need_append_buffer_lock= 0;
|
||||
#endif
|
||||
|
||||
if (info->type == WRITE_CACHE || append_cache)
|
||||
{
|
||||
@@ -1726,7 +1742,6 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
|
||||
if ((length=(size_t) (info->write_pos - info->write_buffer)))
|
||||
{
|
||||
#ifdef THREAD
|
||||
/*
|
||||
In case of a shared I/O cache with a writer we do direct write
|
||||
cache to read cache copy. Do it before the write here so that
|
||||
@@ -1735,7 +1750,6 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
*/
|
||||
if (info->share)
|
||||
copy_to_read_buffer(info, info->write_buffer, length);
|
||||
#endif
|
||||
|
||||
pos_in_file=info->pos_in_file;
|
||||
/*
|
||||
@@ -1744,7 +1758,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
*/
|
||||
if (!append_cache && info->seek_not_done)
|
||||
{ /* File touched, do seek */
|
||||
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
|
||||
if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) ==
|
||||
MY_FILEPOS_ERROR)
|
||||
{
|
||||
UNLOCK_APPEND_BUFFER;
|
||||
@@ -1758,7 +1772,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
info->write_end= (info->write_buffer+info->buffer_length-
|
||||
((pos_in_file+length) & (IO_SIZE-1)));
|
||||
|
||||
if (my_write(info->file,info->write_buffer,length,
|
||||
if (mysql_file_write(info->file,info->write_buffer,length,
|
||||
info->myflags | MY_NABP))
|
||||
info->error= -1;
|
||||
else
|
||||
@@ -1770,7 +1784,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
else
|
||||
{
|
||||
info->end_of_file+=(info->write_pos-info->append_read_pos);
|
||||
DBUG_ASSERT(info->end_of_file == my_tell(info->file,MYF(0)));
|
||||
DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
|
||||
}
|
||||
|
||||
info->append_read_pos=info->write_pos=info->write_buffer;
|
||||
@@ -1814,13 +1828,11 @@ int end_io_cache(IO_CACHE *info)
|
||||
DBUG_ENTER("end_io_cache");
|
||||
DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info));
|
||||
|
||||
#ifdef THREAD
|
||||
/*
|
||||
Every thread must call remove_io_thread(). The last one destroys
|
||||
the share elements.
|
||||
*/
|
||||
DBUG_ASSERT(!info->share || !info->share->total_threads);
|
||||
#endif
|
||||
|
||||
if ((pre_close=info->pre_close))
|
||||
{
|
||||
@@ -1832,16 +1844,14 @@ int end_io_cache(IO_CACHE *info)
|
||||
info->alloced_buffer=0;
|
||||
if (info->file != -1) /* File doesn't exist */
|
||||
error= my_b_flush_io_cache(info,1);
|
||||
my_free((uchar*) info->buffer,MYF(MY_WME));
|
||||
my_free(info->buffer);
|
||||
info->buffer=info->read_pos=(uchar*) 0;
|
||||
}
|
||||
if (info->type == SEQ_READ_APPEND)
|
||||
{
|
||||
/* Destroy allocated mutex */
|
||||
info->type= TYPE_NOT_SET;
|
||||
#ifdef THREAD
|
||||
pthread_mutex_destroy(&info->append_buffer_lock);
|
||||
#endif
|
||||
mysql_mutex_destroy(&info->append_buffer_lock);
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
} /* end_io_cache */
|
||||
@@ -1918,7 +1928,7 @@ int main(int argc, char** argv)
|
||||
total_bytes += 4+block_size;
|
||||
}
|
||||
close_file(&sra_cache);
|
||||
my_free(block,MYF(MY_WME));
|
||||
my_free(block);
|
||||
if (!my_stat(fname,&status,MYF(MY_WME)))
|
||||
die("%s failed to stat, but I had just closed it,\
|
||||
wonder how that happened");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,7 +17,6 @@
|
||||
More functions to be used with IO_CACHE files
|
||||
*/
|
||||
|
||||
#define MAP_TO_USE_RAID
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <stdarg.h>
|
||||
@@ -70,6 +69,16 @@ my_b_copy_to_file(IO_CACHE *cache, FILE *file)
|
||||
|
||||
my_off_t my_b_append_tell(IO_CACHE* info)
|
||||
{
|
||||
/*
|
||||
Sometimes we want to make sure that the variable is not put into
|
||||
a register in debugging mode so we can see its value in the core
|
||||
*/
|
||||
#ifndef DBUG_OFF
|
||||
# define dbug_volatile volatile
|
||||
#else
|
||||
# define dbug_volatile
|
||||
#endif
|
||||
|
||||
/*
|
||||
Prevent optimizer from putting res in a register when debugging
|
||||
we need this to be able to see the value of res when the assert fails
|
||||
@@ -81,9 +90,8 @@ my_off_t my_b_append_tell(IO_CACHE* info)
|
||||
from messing with the variables that we need in order to provide the
|
||||
answer to the question.
|
||||
*/
|
||||
#ifdef THREAD
|
||||
pthread_mutex_lock(&info->append_buffer_lock);
|
||||
#endif
|
||||
mysql_mutex_lock(&info->append_buffer_lock);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
/*
|
||||
Make sure EOF is where we think it is. Note that we cannot just use
|
||||
@@ -103,9 +111,7 @@ my_off_t my_b_append_tell(IO_CACHE* info)
|
||||
}
|
||||
#endif
|
||||
res = info->end_of_file + (info->write_pos-info->append_read_pos);
|
||||
#ifdef THREAD
|
||||
pthread_mutex_unlock(&info->append_buffer_lock);
|
||||
#endif
|
||||
mysql_mutex_unlock(&info->append_buffer_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
|
||||
b) see if there is a better way to make it work
|
||||
*/
|
||||
if (info->type == SEQ_READ_APPEND)
|
||||
VOID(flush_io_cache(info));
|
||||
(void) flush_io_cache(info);
|
||||
|
||||
offset=(pos - info->pos_in_file);
|
||||
|
||||
@@ -163,7 +169,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
|
||||
info->write_pos = info->write_buffer + offset;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
VOID(flush_io_cache(info));
|
||||
(void) flush_io_cache(info);
|
||||
/* Correct buffer end so that we write in increments of IO_SIZE */
|
||||
info->write_end=(info->write_buffer+info->buffer_length-
|
||||
(pos & (IO_SIZE-1)));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,361 @@
|
||||
/* Copyright (C) 2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Handling of multiple key caches
|
||||
|
||||
The idea is to have a thread safe hash on the table name,
|
||||
with a default key cache value that is returned if the table name is not in
|
||||
the cache.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <keycache.h>
|
||||
#include <hash.h>
|
||||
#include <m_string.h>
|
||||
|
||||
/*****************************************************************************
|
||||
General functions to handle SAFE_HASH objects.
|
||||
|
||||
A SAFE_HASH object is used to store the hash, the mutex and default value
|
||||
needed by the rest of the key cache code.
|
||||
This is a separate struct to make it easy to later reuse the code for other
|
||||
purposes
|
||||
|
||||
All entries are linked in a list to allow us to traverse all elements
|
||||
and delete selected ones. (HASH doesn't allow any easy ways to do this).
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
Struct to store a key and pointer to object
|
||||
*/
|
||||
|
||||
typedef struct st_safe_hash_entry
|
||||
{
|
||||
uchar *key;
|
||||
uint length;
|
||||
uchar *data;
|
||||
struct st_safe_hash_entry *next, **prev;
|
||||
} SAFE_HASH_ENTRY;
|
||||
|
||||
|
||||
typedef struct st_safe_hash_with_default
|
||||
{
|
||||
rw_lock_t mutex;
|
||||
HASH hash;
|
||||
uchar *default_value;
|
||||
SAFE_HASH_ENTRY *root;
|
||||
} SAFE_HASH;
|
||||
|
||||
|
||||
/*
|
||||
Free a SAFE_HASH_ENTRY
|
||||
|
||||
This function is called by the hash object on delete
|
||||
*/
|
||||
|
||||
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
|
||||
{
|
||||
DBUG_ENTER("free_assign_entry");
|
||||
my_free(entry);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Get key and length for a SAFE_HASH_ENTRY */
|
||||
|
||||
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
*length=entry->length;
|
||||
return (uchar*) entry->key;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Init a SAFE_HASH object
|
||||
|
||||
SYNOPSIS
|
||||
safe_hash_init()
|
||||
hash safe_hash handler
|
||||
elements Expected max number of elements
|
||||
default_value default value
|
||||
|
||||
NOTES
|
||||
In case of error we set hash->default_value to 0 to allow one to call
|
||||
safe_hash_free on an object that couldn't be initialized.
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error
|
||||
*/
|
||||
|
||||
static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
|
||||
uchar *default_value)
|
||||
{
|
||||
DBUG_ENTER("safe_hash");
|
||||
if (my_hash_init(&hash->hash, &my_charset_bin, elements,
|
||||
0, 0, (my_hash_get_key) safe_hash_entry_get,
|
||||
(void (*)(void*)) safe_hash_entry_free, 0))
|
||||
{
|
||||
hash->default_value= 0;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
my_rwlock_init(&hash->mutex, 0);
|
||||
hash->default_value= default_value;
|
||||
hash->root= 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Free a SAFE_HASH object
|
||||
|
||||
NOTES
|
||||
This is safe to call on any object that has been sent to safe_hash_init()
|
||||
*/
|
||||
|
||||
static void safe_hash_free(SAFE_HASH *hash)
|
||||
{
|
||||
/*
|
||||
Test if safe_hash_init succeeded. This will also guard us against multiple
|
||||
free calls.
|
||||
*/
|
||||
if (hash->default_value)
|
||||
{
|
||||
my_hash_free(&hash->hash);
|
||||
rwlock_destroy(&hash->mutex);
|
||||
hash->default_value=0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Return the value stored for a key or default value if no key
|
||||
*/
|
||||
|
||||
static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
|
||||
{
|
||||
uchar *result;
|
||||
DBUG_ENTER("safe_hash_search");
|
||||
rw_rdlock(&hash->mutex);
|
||||
result= my_hash_search(&hash->hash, key, length);
|
||||
rw_unlock(&hash->mutex);
|
||||
if (!result)
|
||||
result= hash->default_value;
|
||||
else
|
||||
result= ((SAFE_HASH_ENTRY*) result)->data;
|
||||
DBUG_PRINT("exit",("data: 0x%lx", (long) result));
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Associate a key with some data
|
||||
|
||||
SYONOPSIS
|
||||
safe_hash_set()
|
||||
hash Hash handle
|
||||
key key (path to table etc..)
|
||||
length Length of key
|
||||
data data to to associate with the data
|
||||
|
||||
NOTES
|
||||
This can be used both to insert a new entry and change an existing
|
||||
entry.
|
||||
If one associates a key with the default key cache, the key is deleted
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error (Can only be EOM). In this case my_message() is called.
|
||||
*/
|
||||
|
||||
static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
|
||||
uchar *data)
|
||||
{
|
||||
SAFE_HASH_ENTRY *entry;
|
||||
my_bool error= 0;
|
||||
DBUG_ENTER("safe_hash_set");
|
||||
DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
|
||||
|
||||
rw_wrlock(&hash->mutex);
|
||||
entry= (SAFE_HASH_ENTRY*) my_hash_search(&hash->hash, key, length);
|
||||
|
||||
if (data == hash->default_value)
|
||||
{
|
||||
/*
|
||||
The key is to be associated with the default entry. In this case
|
||||
we can just delete the entry (if it existed) from the hash as a
|
||||
search will return the default entry
|
||||
*/
|
||||
if (!entry) /* nothing to do */
|
||||
goto end;
|
||||
/* unlink entry from list */
|
||||
if ((*entry->prev= entry->next))
|
||||
entry->next->prev= entry->prev;
|
||||
my_hash_delete(&hash->hash, (uchar*) entry);
|
||||
goto end;
|
||||
}
|
||||
if (entry)
|
||||
{
|
||||
/* Entry existed; Just change the pointer to point at the new data */
|
||||
entry->data= data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
|
||||
MYF(MY_WME))))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
entry->key= (uchar*) (entry +1);
|
||||
memcpy((char*) entry->key, (char*) key, length);
|
||||
entry->length= length;
|
||||
entry->data= data;
|
||||
/* Link entry to list */
|
||||
if ((entry->next= hash->root))
|
||||
entry->next->prev= &entry->next;
|
||||
entry->prev= &hash->root;
|
||||
hash->root= entry;
|
||||
if (my_hash_insert(&hash->hash, (uchar*) entry))
|
||||
{
|
||||
/* This can only happen if hash got out of memory */
|
||||
my_free(entry);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
rw_unlock(&hash->mutex);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Change all entres with one data value to another data value
|
||||
|
||||
SYONOPSIS
|
||||
safe_hash_change()
|
||||
hash Hash handle
|
||||
old_data Old data
|
||||
new_data Change all 'old_data' to this
|
||||
|
||||
NOTES
|
||||
We use the linked list to traverse all elements in the hash as
|
||||
this allows us to delete elements in the case where 'new_data' is the
|
||||
default value.
|
||||
*/
|
||||
|
||||
static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
|
||||
{
|
||||
SAFE_HASH_ENTRY *entry, *next;
|
||||
DBUG_ENTER("safe_hash_set");
|
||||
|
||||
rw_wrlock(&hash->mutex);
|
||||
|
||||
for (entry= hash->root ; entry ; entry= next)
|
||||
{
|
||||
next= entry->next;
|
||||
if (entry->data == old_data)
|
||||
{
|
||||
if (new_data == hash->default_value)
|
||||
{
|
||||
if ((*entry->prev= entry->next))
|
||||
entry->next->prev= entry->prev;
|
||||
my_hash_delete(&hash->hash, (uchar*) entry);
|
||||
}
|
||||
else
|
||||
entry->data= new_data;
|
||||
}
|
||||
}
|
||||
|
||||
rw_unlock(&hash->mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Functions to handle the key cache objects
|
||||
*****************************************************************************/
|
||||
|
||||
/* Variable to store all key cache objects */
|
||||
static SAFE_HASH key_cache_hash;
|
||||
|
||||
|
||||
my_bool multi_keycache_init(void)
|
||||
{
|
||||
return safe_hash_init(&key_cache_hash, 16, (uchar*) dflt_key_cache);
|
||||
}
|
||||
|
||||
|
||||
void multi_keycache_free(void)
|
||||
{
|
||||
safe_hash_free(&key_cache_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
Get a key cache to be used for a specific table.
|
||||
|
||||
SYNOPSIS
|
||||
multi_key_cache_search()
|
||||
key key to find (usually table path)
|
||||
uint length Length of key.
|
||||
|
||||
NOTES
|
||||
This function is coded in such a way that we will return the
|
||||
default key cache even if one never called multi_keycache_init.
|
||||
This will ensure that it works with old MyISAM clients.
|
||||
|
||||
RETURN
|
||||
key cache to use
|
||||
*/
|
||||
|
||||
KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
|
||||
{
|
||||
if (!key_cache_hash.hash.records)
|
||||
return dflt_key_cache;
|
||||
return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Assosiate a key cache with a key
|
||||
|
||||
|
||||
SYONOPSIS
|
||||
multi_key_cache_set()
|
||||
key key (path to table etc..)
|
||||
length Length of key
|
||||
key_cache cache to assococite with the table
|
||||
|
||||
NOTES
|
||||
This can be used both to insert a new entry and change an existing
|
||||
entry
|
||||
*/
|
||||
|
||||
|
||||
my_bool multi_key_cache_set(const uchar *key, uint length,
|
||||
KEY_CACHE *key_cache)
|
||||
{
|
||||
return safe_hash_set(&key_cache_hash, key, length, (uchar*) key_cache);
|
||||
}
|
||||
|
||||
|
||||
void multi_key_cache_change(KEY_CACHE *old_data,
|
||||
KEY_CACHE *new_data)
|
||||
{
|
||||
safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
|
||||
}
|
||||
@@ -34,7 +34,7 @@ char * my_load_path(char * to, const char *path,
|
||||
|
||||
if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
|
||||
test_if_hard_path(path))
|
||||
VOID(strnmov(buff, path, FN_REFLEN));
|
||||
(void) strnmov(buff, path, FN_REFLEN);
|
||||
else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) ||
|
||||
(is_prefix(path,FN_PARENTDIR)) ||
|
||||
! own_path_prefix)
|
||||
@@ -42,12 +42,12 @@ char * my_load_path(char * to, const char *path,
|
||||
if (is_cur)
|
||||
is_cur=2; /* Remove current dir */
|
||||
if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)+is_cur),MYF(0)))
|
||||
VOID(strncat(buff, path+is_cur, FN_REFLEN-1));
|
||||
(void) strncat(buff, path+is_cur, FN_REFLEN-1);
|
||||
else
|
||||
VOID(strnmov(buff, path, FN_REFLEN)); /* Return org file name */
|
||||
(void) strnmov(buff, path, FN_REFLEN); /* Return org file name */
|
||||
}
|
||||
else
|
||||
VOID(strxnmov(buff, FN_REFLEN, own_path_prefix,path, NullS));
|
||||
(void) strxnmov(buff, FN_REFLEN, own_path_prefix, path, NullS);
|
||||
strnmov(to, buff, FN_REFLEN);
|
||||
to[FN_REFLEN-1]= '\0';
|
||||
DBUG_PRINT("exit",("to: %s",to));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,13 +18,8 @@
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#include <rms.h>
|
||||
#include <iodef.h>
|
||||
#include <descrip.h>
|
||||
#endif /* VMS */
|
||||
|
||||
static char * NEAR_F expand_tilde(char * *path);
|
||||
static char * expand_tilde(char **path);
|
||||
|
||||
/* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
|
||||
/* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
|
||||
@@ -197,7 +192,8 @@ size_t cleanup_dirname(register char *to, const char *from)
|
||||
end_parentdir=pos;
|
||||
while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
|
||||
pos--;
|
||||
if (pos[1] == FN_HOMELIB || memcmp(pos,parent,length) == 0)
|
||||
if (pos[1] == FN_HOMELIB ||
|
||||
(pos > start && memcmp(pos, parent, length) == 0))
|
||||
{ /* Don't remove ~user/ */
|
||||
pos=strmov(end_parentdir+1,parent);
|
||||
*pos=FN_LIBCHAR;
|
||||
@@ -300,8 +296,7 @@ size_t normalize_dirname(char *to, const char *from)
|
||||
|
||||
/*
|
||||
Despite the name, this actually converts the name to the system's
|
||||
format (TODO: rip out the non-working VMS stuff and name this
|
||||
properly).
|
||||
format (TODO: name this properly).
|
||||
*/
|
||||
(void) intern_filename(buff, from);
|
||||
length= strlen(buff); /* Fix that '/' is last */
|
||||
@@ -377,7 +372,7 @@ size_t unpack_dirname(char * to, const char *from)
|
||||
/* Expand tilde to home or user-directory */
|
||||
/* Path is reset to point at FN_LIBCHAR after ~xxx */
|
||||
|
||||
static char * NEAR_F expand_tilde(char * *path)
|
||||
static char * expand_tilde(char **path)
|
||||
{
|
||||
if (path[0][0] == FN_LIBCHAR)
|
||||
return home_dir; /* ~/ expanded to home */
|
||||
@@ -443,73 +438,10 @@ size_t unpack_filename(char * to, const char *from)
|
||||
/* Used before system command's like open(), create() .. */
|
||||
/* Returns used length of to; total length should be FN_REFLEN */
|
||||
|
||||
size_t system_filename(char * to, const char *from)
|
||||
size_t system_filename(char *to, const char *from)
|
||||
{
|
||||
#ifndef FN_C_BEFORE_DIR
|
||||
return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
|
||||
#else /* VMS */
|
||||
|
||||
/* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
|
||||
/* change 'dev:xxx' to 'dev:xxx' */
|
||||
/* change './xxx' to 'xxx' */
|
||||
/* change './lib/' or lib/ to '[.lib]' */
|
||||
/* change '/x/y/z to '[x.y]x' */
|
||||
/* change 'dev:/x' to 'dev:[000000]x' */
|
||||
|
||||
int libchar_found;
|
||||
size_t length;
|
||||
char * to_pos,from_pos,pos;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("system_filename");
|
||||
|
||||
libchar_found=0;
|
||||
(void) strmov(buff,from); /* If to == from */
|
||||
from_pos= buff;
|
||||
if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
|
||||
{
|
||||
pos++;
|
||||
to_pos=strnmov(to,from_pos,(size_t) (pos-from_pos));
|
||||
from_pos=pos;
|
||||
}
|
||||
else
|
||||
to_pos=to;
|
||||
|
||||
if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
|
||||
from_pos+=2; /* Skip './' */
|
||||
if (strchr(from_pos,FN_LIBCHAR))
|
||||
{
|
||||
*(to_pos++) = FN_C_BEFORE_DIR;
|
||||
if (strinstr(from_pos,FN_ROOTDIR) == 1)
|
||||
{
|
||||
from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
|
||||
if (! strchr(from_pos,FN_LIBCHAR))
|
||||
{ /* No dir, use [000000] */
|
||||
to_pos=strmov(to_pos,FN_C_ROOT_DIR);
|
||||
libchar_found++;
|
||||
}
|
||||
}
|
||||
else
|
||||
*(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
|
||||
|
||||
while ((pos=strchr(from_pos,FN_LIBCHAR)))
|
||||
{
|
||||
if (libchar_found++)
|
||||
*(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
|
||||
if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
|
||||
from_pos+strlen(FN_PARENTDIR) == pos)
|
||||
to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
|
||||
else
|
||||
to_pos=strnmov(to_pos,from_pos,(size_t) (pos-from_pos));
|
||||
from_pos=pos+1;
|
||||
}
|
||||
*(to_pos++)=FN_C_AFTER_DIR;
|
||||
}
|
||||
length= (size_t) (strmov(to_pos,from_pos)-to);
|
||||
DBUG_PRINT("exit",("name: '%s'",to));
|
||||
DBUG_RETURN(length);
|
||||
#endif
|
||||
} /* system_filename */
|
||||
|
||||
}
|
||||
|
||||
/* Fix a filename to intern (UNIX format) */
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ char * my_path(char * to, const char *progname,
|
||||
((prog=getenv("_")) != 0 &&
|
||||
dirname_part(to, prog, &to_length))))
|
||||
{
|
||||
VOID(intern_filename(to,to));
|
||||
(void) intern_filename(to,to);
|
||||
if (!test_if_hard_path(to))
|
||||
{
|
||||
if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
|
||||
@@ -60,11 +60,11 @@ char * my_path(char * to, const char *progname,
|
||||
end= (char*) "/my/";
|
||||
#endif
|
||||
}
|
||||
VOID(intern_filename(to,end));
|
||||
(void) intern_filename(to,end);
|
||||
to=strend(to);
|
||||
if (to != start && to[-1] != FN_LIBCHAR)
|
||||
*to++ = FN_LIBCHAR;
|
||||
VOID(strmov(to,own_pathname_part));
|
||||
(void) strmov(to,own_pathname_part);
|
||||
}
|
||||
DBUG_PRINT("exit",("to: '%s'",start));
|
||||
DBUG_RETURN(start);
|
||||
@@ -78,9 +78,6 @@ char * my_path(char * to, const char *progname,
|
||||
#define F_OK 0
|
||||
#define PATH_SEP ';'
|
||||
#define PROGRAM_EXTENSION ".exe"
|
||||
#elif defined(__NETWARE__)
|
||||
#define PATH_SEP ';'
|
||||
#define PROGRAM_EXTENSION ".nlm"
|
||||
#else
|
||||
#define PATH_SEP ':'
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* qsort that sends one extra argument to the compare subrutine */
|
||||
|
||||
#define QSORT_EXTRA_CMP_ARGUMENT
|
||||
#include "mf_qsort.c"
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Radixsort for pointers to fixed length strings.
|
||||
A very quick sort for not to long (< 20 char) strings.
|
||||
Neads a extra buffers of number_of_elements pointers but is
|
||||
2-3 times faster than quicksort
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* Radixsort */
|
||||
|
||||
void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_t size_of_element, uchar **buffer)
|
||||
{
|
||||
uchar **end,**ptr,**buffer_ptr;
|
||||
uint32 *count_ptr,*count_end,count[256];
|
||||
int pass;
|
||||
|
||||
end=base+number_of_elements; count_end=count+256;
|
||||
for (pass=(int) size_of_element-1 ; pass >= 0 ; pass--)
|
||||
{
|
||||
bzero((uchar*) count,sizeof(uint32)*256);
|
||||
for (ptr= base ; ptr < end ; ptr++)
|
||||
count[ptr[0][pass]]++;
|
||||
if (count[0] == number_of_elements)
|
||||
goto next;
|
||||
for (count_ptr=count+1 ; count_ptr < count_end ; count_ptr++)
|
||||
{
|
||||
if (*count_ptr == number_of_elements)
|
||||
goto next;
|
||||
(*count_ptr)+= *(count_ptr-1);
|
||||
}
|
||||
for (ptr= end ; ptr-- != base ;)
|
||||
buffer[--count[ptr[0][pass]]]= *ptr;
|
||||
for (ptr=base, buffer_ptr=buffer ; ptr < end ;)
|
||||
(*ptr++) = *buffer_ptr++;
|
||||
next:;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Kopierar biblioteksstrukturen och extensionen fr}n ett filnamn */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Copy directory and/or extension between filenames.
|
||||
(For the meaning of 'flag', check mf_format.c)
|
||||
'to' may be equal to 'name'.
|
||||
Returns 'to'.
|
||||
*/
|
||||
|
||||
char * fn_same(char *to, const char *name, int flag)
|
||||
{
|
||||
char dev[FN_REFLEN];
|
||||
const char *ext;
|
||||
size_t dev_length;
|
||||
DBUG_ENTER("fn_same");
|
||||
DBUG_PRINT("enter",("to: %s name: %s flag: %d",to,name,flag));
|
||||
|
||||
if ((ext=strrchr(name+dirname_part(dev, name, &dev_length),FN_EXTCHAR)) == 0)
|
||||
ext="";
|
||||
|
||||
DBUG_RETURN(fn_format(to,to,dev,ext,flag));
|
||||
} /* fn_same */
|
||||
@@ -13,30 +13,29 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* thread safe version of some common functions */
|
||||
/* Sort of string pointers in string-order with radix or qsort */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* for thread safe my_inet_ntoa */
|
||||
#if !defined(__WIN__)
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#endif /* !defined(__WIN__) */
|
||||
|
||||
void my_inet_ntoa(struct in_addr in, char *buf)
|
||||
void my_string_ptr_sort(uchar *base, uint items, size_t size)
|
||||
{
|
||||
char *ptr;
|
||||
pthread_mutex_lock(&THR_LOCK_net);
|
||||
ptr=inet_ntoa(in);
|
||||
strmov(buf,ptr);
|
||||
pthread_mutex_unlock(&THR_LOCK_net);
|
||||
#if INT_MAX > 65536L
|
||||
uchar **ptr=0;
|
||||
|
||||
if (size <= 20 && items >= 1000 && items < 100000 &&
|
||||
(ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
|
||||
{
|
||||
radixsort_for_str_ptr((uchar**) base,items,size,ptr);
|
||||
my_free(ptr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (size && items)
|
||||
{
|
||||
my_qsort2(base,items, sizeof(uchar*), get_ptr_compare(size),
|
||||
(void*) &size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/****************************************************************
|
||||
* SOUNDEX ALGORITHM in C *
|
||||
* *
|
||||
* The basic Algorithm source is taken from EDN Nov. *
|
||||
* 14, 1985 pg. 36. *
|
||||
* *
|
||||
* As a test Those in Illinois will find that the *
|
||||
* first group of numbers in their drivers license *
|
||||
* number is the soundex number for their last name. *
|
||||
* *
|
||||
* RHW PC-IBBS ID. #1230 *
|
||||
* *
|
||||
* As an extension if remove_garbage is set then all non- *
|
||||
* alpha characters are skipped *
|
||||
* *
|
||||
* Note, that this implementation corresponds to the *
|
||||
* original version of the algorithm, not to the more *
|
||||
* popular "enhanced" version, described by Knuth. *
|
||||
****************************************************************/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_ctype.h>
|
||||
#include "my_static.h"
|
||||
|
||||
static char get_scode(CHARSET_INFO * cs, char **ptr,pbool remove_garbage);
|
||||
|
||||
/* outputed string is 4 byte long */
|
||||
/* out_pntr can be == in_pntr */
|
||||
|
||||
void soundex(CHARSET_INFO * cs,register char * out_pntr, char * in_pntr,
|
||||
pbool remove_garbage)
|
||||
{
|
||||
char ch,last_ch;
|
||||
reg3 char * end;
|
||||
register uchar *map=cs->to_upper;
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (*in_pntr && !my_isalpha(cs,*in_pntr)) /* Skip pre-space */
|
||||
in_pntr++;
|
||||
}
|
||||
*out_pntr++ = map[(uchar)*in_pntr]; /* Copy first letter */
|
||||
last_ch = get_scode(cs,&in_pntr,0); /* code of the first letter */
|
||||
/* for the first 'double-letter */
|
||||
/* check. */
|
||||
end=out_pntr+3; /* Loop on input letters until */
|
||||
/* end of input (null) or output */
|
||||
/* letter code count = 3 */
|
||||
|
||||
in_pntr++;
|
||||
while (out_pntr < end && (ch = get_scode(cs,&in_pntr,remove_garbage)) != 0)
|
||||
{
|
||||
in_pntr++;
|
||||
if ((ch != '0') && (ch != last_ch)) /* if not skipped or double */
|
||||
{
|
||||
*out_pntr++ = ch; /* letter, copy to output */
|
||||
} /* for next double-letter check */
|
||||
last_ch = ch; /* save code of last input letter */
|
||||
}
|
||||
while (out_pntr < end)
|
||||
*out_pntr++ = '0';
|
||||
*out_pntr=0; /* end string */
|
||||
return;
|
||||
} /* soundex */
|
||||
|
||||
|
||||
/*
|
||||
If alpha, map input letter to soundex code.
|
||||
If not alpha and remove_garbage is set then skip to next char
|
||||
else return 0
|
||||
*/
|
||||
|
||||
static char get_scode(CHARSET_INFO * cs,char **ptr, pbool remove_garbage)
|
||||
{
|
||||
uchar ch;
|
||||
|
||||
if (remove_garbage)
|
||||
{
|
||||
while (**ptr && !my_isalpha(cs,**ptr))
|
||||
(*ptr)++;
|
||||
}
|
||||
ch=my_toupper(cs,**ptr);
|
||||
if (ch < 'A' || ch > 'Z')
|
||||
{
|
||||
if (my_isalpha(cs,ch)) /* If extended alfa (country spec) */
|
||||
return '0'; /* threat as vokal */
|
||||
return 0; /* Can't map */
|
||||
}
|
||||
return(soundex_map[ch-'A']);
|
||||
} /* get_scode */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#if defined(__WIN__)
|
||||
#define DELIM ';'
|
||||
#else
|
||||
#define DELIM ':'
|
||||
#endif
|
||||
|
||||
my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist)
|
||||
{
|
||||
char *end, *copy;
|
||||
char buff[FN_REFLEN];
|
||||
DBUG_ENTER("init_tmpdir");
|
||||
DBUG_PRINT("enter", ("pathlist: %s", pathlist ? pathlist : "NULL"));
|
||||
|
||||
mysql_mutex_init(key_TMPDIR_mutex, &tmpdir->mutex, MY_MUTEX_INIT_FAST);
|
||||
if (my_init_dynamic_array(&tmpdir->full_list, sizeof(char*), 1, 5))
|
||||
goto err;
|
||||
if (!pathlist || !pathlist[0])
|
||||
{
|
||||
/* Get default temporary directory */
|
||||
pathlist=getenv("TMPDIR"); /* Use this if possible */
|
||||
#if defined(__WIN__)
|
||||
if (!pathlist)
|
||||
pathlist=getenv("TEMP");
|
||||
if (!pathlist)
|
||||
pathlist=getenv("TMP");
|
||||
#endif
|
||||
if (!pathlist || !pathlist[0])
|
||||
pathlist=(char*) P_tmpdir;
|
||||
}
|
||||
do
|
||||
{
|
||||
size_t length;
|
||||
end=strcend(pathlist, DELIM);
|
||||
strmake(buff, pathlist, (uint) (end-pathlist));
|
||||
length= cleanup_dirname(buff, buff);
|
||||
if (!(copy= my_strndup(buff, length, MYF(MY_WME))) ||
|
||||
insert_dynamic(&tmpdir->full_list, (uchar*) ©))
|
||||
DBUG_RETURN(TRUE);
|
||||
pathlist=end+1;
|
||||
}
|
||||
while (*end);
|
||||
freeze_size(&tmpdir->full_list);
|
||||
tmpdir->list=(char **)tmpdir->full_list.buffer;
|
||||
tmpdir->max=tmpdir->full_list.elements-1;
|
||||
tmpdir->cur=0;
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
delete_dynamic(&tmpdir->full_list); /* Safe to free */
|
||||
mysql_mutex_destroy(&tmpdir->mutex);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
char *my_tmpdir(MY_TMPDIR *tmpdir)
|
||||
{
|
||||
char *dir;
|
||||
if (!tmpdir->max)
|
||||
return tmpdir->list[0];
|
||||
mysql_mutex_lock(&tmpdir->mutex);
|
||||
dir=tmpdir->list[tmpdir->cur];
|
||||
tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1;
|
||||
mysql_mutex_unlock(&tmpdir->mutex);
|
||||
return dir;
|
||||
}
|
||||
|
||||
void free_tmpdir(MY_TMPDIR *tmpdir)
|
||||
{
|
||||
uint i;
|
||||
if (!tmpdir->full_list.elements)
|
||||
return;
|
||||
for (i=0; i<=tmpdir->max; i++)
|
||||
my_free(tmpdir->list[i]);
|
||||
delete_dynamic(&tmpdir->full_list);
|
||||
mysql_mutex_destroy(&tmpdir->mutex);
|
||||
}
|
||||
|
||||
@@ -100,16 +100,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
||||
my_errno= tmp;
|
||||
}
|
||||
|
||||
#elif defined(_ZTC__)
|
||||
if (!dir)
|
||||
dir=getenv("TMPDIR");
|
||||
if ((res=tempnam((char*) dir,(char *) prefix)))
|
||||
{
|
||||
strmake(to,res,FN_REFLEN-1);
|
||||
(*free)(res);
|
||||
file=my_create(to, 0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
|
||||
}
|
||||
#elif defined(HAVE_MKSTEMP) && !defined(__NETWARE__)
|
||||
#elif defined(HAVE_MKSTEMP)
|
||||
{
|
||||
char prefix_buff[30];
|
||||
uint pfx_len;
|
||||
@@ -143,9 +134,7 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
||||
}
|
||||
#elif defined(HAVE_TEMPNAM)
|
||||
{
|
||||
#if !defined(__NETWARE__)
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
char *res,**old_env,*temp_env[1];
|
||||
if (dir && !dir[0])
|
||||
@@ -154,14 +143,14 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
||||
to[1]= 0;
|
||||
dir=to;
|
||||
}
|
||||
#if !defined(__NETWARE__)
|
||||
|
||||
old_env= (char**) environ;
|
||||
if (dir)
|
||||
{ /* Don't use TMPDIR if dir is given */
|
||||
environ=(const char**) temp_env;
|
||||
temp_env[0]=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((res=tempnam((char*) dir, (char*) prefix)))
|
||||
{
|
||||
strmake(to,res,FN_REFLEN-1);
|
||||
@@ -176,9 +165,8 @@ File create_temp_file(char *to, const char *dir, const char *prefix,
|
||||
{
|
||||
DBUG_PRINT("error",("Got error: %d from tempnam",errno));
|
||||
}
|
||||
#if !defined(__NETWARE__)
|
||||
|
||||
environ=(const char**) old_env;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#error No implementation found for create_temp_file
|
||||
|
||||
@@ -16,10 +16,15 @@
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* convert filename to unix style filename */
|
||||
/* If MSDOS converts '\' to '/' */
|
||||
/**
|
||||
Convert filename to unix style filename.
|
||||
|
||||
void to_unix_path(char * to __attribute__((unused)))
|
||||
@remark On Windows, converts '\' to '/'.
|
||||
|
||||
@param to A pathname.
|
||||
*/
|
||||
|
||||
void to_unix_path(char *to __attribute__((unused)))
|
||||
{
|
||||
#if FN_LIBCHAR != '/'
|
||||
{
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/* Copyright (C) 2002 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/*
|
||||
Implementation of AES Encryption for MySQL
|
||||
Initial version by Peter Zaitsev June 2002
|
||||
*/
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include "my_aes.h"
|
||||
|
||||
enum encrypt_dir { AES_ENCRYPT, AES_DECRYPT };
|
||||
|
||||
#define AES_BLOCK_SIZE 16 /* Block size in bytes */
|
||||
|
||||
#define AES_BAD_DATA -1 /* If bad data discovered during decoding */
|
||||
|
||||
|
||||
/* The structure for key information */
|
||||
typedef struct {
|
||||
int nr; /* Number of rounds */
|
||||
uint32 rk[4*(AES_MAXNR + 1)]; /* key schedule */
|
||||
} KEYINSTANCE;
|
||||
|
||||
|
||||
/*
|
||||
This is internal function just keeps joint code of Key generation
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_create_key()
|
||||
aes_key Address of Key Instance to be created
|
||||
direction Direction (are we encoding or decoding)
|
||||
key Key to use for real key creation
|
||||
key_length Length of the key
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
RESULT
|
||||
0 ok
|
||||
-1 Error Note: The current impementation never returns this
|
||||
*/
|
||||
|
||||
static int my_aes_create_key(KEYINSTANCE *aes_key,
|
||||
enum encrypt_dir direction, const char *key,
|
||||
int key_length)
|
||||
{
|
||||
uint8 rkey[AES_KEY_LENGTH/8]; /* The real key to be used for encryption */
|
||||
uint8 *rkey_end=rkey+AES_KEY_LENGTH/8; /* Real key boundary */
|
||||
uint8 *ptr; /* Start of the real key*/
|
||||
const char *sptr; /* Start of the working key */
|
||||
const char *key_end=key+key_length; /* Working key boundary*/
|
||||
|
||||
bzero((char*) rkey,AES_KEY_LENGTH/8); /* Set initial key */
|
||||
|
||||
for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
|
||||
{
|
||||
if (ptr == rkey_end)
|
||||
ptr= rkey; /* Just loop over tmp_key until we used all key */
|
||||
*ptr^= (uint8) *sptr;
|
||||
}
|
||||
#ifdef AES_USE_KEY_BITS
|
||||
/*
|
||||
This block is intended to allow more weak encryption if application
|
||||
build with libmysqld needs to correspond to export regulations
|
||||
It should be never used in normal distribution as does not give
|
||||
any speed improvement.
|
||||
To get worse security define AES_USE_KEY_BITS to number of bits
|
||||
you want key to be. It should be divisible by 8
|
||||
|
||||
WARNING: Changing this value results in changing of enryption for
|
||||
all key lengths so altering this value will result in impossibility
|
||||
to decrypt data encrypted with previous value
|
||||
*/
|
||||
#define AES_USE_KEY_BYTES (AES_USE_KEY_BITS/8)
|
||||
/*
|
||||
To get weaker key we use first AES_USE_KEY_BYTES bytes of created key
|
||||
and cyclically copy them until we created all required key length
|
||||
*/
|
||||
for (ptr= rkey+AES_USE_KEY_BYTES, sptr=rkey ; ptr < rkey_end;
|
||||
ptr++,sptr++)
|
||||
{
|
||||
if (sptr == rkey+AES_USE_KEY_BYTES)
|
||||
sptr=rkey;
|
||||
*ptr=*sptr;
|
||||
}
|
||||
#endif
|
||||
if (direction == AES_DECRYPT)
|
||||
aes_key->nr = rijndaelKeySetupDec(aes_key->rk, rkey, AES_KEY_LENGTH);
|
||||
else
|
||||
aes_key->nr = rijndaelKeySetupEnc(aes_key->rk, rkey, AES_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Crypt buffer with AES encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_encrypt()
|
||||
source Pointer to data for encryption
|
||||
source_length Size of encryption data
|
||||
dest Buffer to place encrypted data (must be large enough)
|
||||
key Key to be used for encryption
|
||||
key_length Length of the key. Will handle keys of any length
|
||||
|
||||
RETURN
|
||||
>= 0 Size of encrypted data
|
||||
< 0 Error
|
||||
*/
|
||||
|
||||
int my_aes_encrypt(const char* source, int source_length, char* dest,
|
||||
const char* key, int key_length)
|
||||
{
|
||||
KEYINSTANCE aes_key;
|
||||
uint8 block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
|
||||
int rc; /* result codes */
|
||||
int num_blocks; /* number of complete blocks */
|
||||
char pad_len; /* pad size for the last block */
|
||||
int i;
|
||||
|
||||
if ((rc= my_aes_create_key(&aes_key,AES_ENCRYPT,key,key_length)))
|
||||
return rc;
|
||||
|
||||
num_blocks = source_length/AES_BLOCK_SIZE;
|
||||
|
||||
for (i = num_blocks; i > 0; i--) /* Encode complete blocks */
|
||||
{
|
||||
rijndaelEncrypt(aes_key.rk, aes_key.nr, (const uint8*) source,
|
||||
(uint8*) dest);
|
||||
source+= AES_BLOCK_SIZE;
|
||||
dest+= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* Encode the rest. We always have incomplete block */
|
||||
pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
|
||||
memcpy(block, source, 16 - pad_len);
|
||||
bfill(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
|
||||
rijndaelEncrypt(aes_key.rk, aes_key.nr, block, (uint8*) dest);
|
||||
return AES_BLOCK_SIZE*(num_blocks + 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DeCrypt buffer with AES encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_decrypt()
|
||||
source Pointer to data for decryption
|
||||
source_length Size of encrypted data
|
||||
dest Buffer to place decrypted data (must be large enough)
|
||||
key Key to be used for decryption
|
||||
key_length Length of the key. Will handle keys of any length
|
||||
|
||||
RETURN
|
||||
>= 0 Size of encrypted data
|
||||
< 0 Error
|
||||
*/
|
||||
|
||||
int my_aes_decrypt(const char *source, int source_length, char *dest,
|
||||
const char *key, int key_length)
|
||||
{
|
||||
KEYINSTANCE aes_key;
|
||||
uint8 block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
|
||||
int rc; /* Result codes */
|
||||
int num_blocks; /* Number of complete blocks */
|
||||
uint pad_len; /* Pad size for the last block */
|
||||
int i;
|
||||
|
||||
if ((rc=my_aes_create_key(&aes_key,AES_DECRYPT,key,key_length)))
|
||||
return rc;
|
||||
|
||||
num_blocks = source_length/AES_BLOCK_SIZE;
|
||||
|
||||
if ((source_length != num_blocks*AES_BLOCK_SIZE) || num_blocks ==0 )
|
||||
return AES_BAD_DATA; /* Input size has to be even and at least one block */
|
||||
|
||||
for (i = num_blocks-1; i > 0; i--) /* Decode all but last blocks */
|
||||
{
|
||||
rijndaelDecrypt(aes_key.rk, aes_key.nr, (const uint8*) source,
|
||||
(uint8*) dest);
|
||||
source+= AES_BLOCK_SIZE;
|
||||
dest+= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
rijndaelDecrypt(aes_key.rk, aes_key.nr, (const uint8*) source, block);
|
||||
/* Use last char in the block as size */
|
||||
pad_len = (uint) (uchar) block[AES_BLOCK_SIZE-1];
|
||||
|
||||
if (pad_len > AES_BLOCK_SIZE)
|
||||
return AES_BAD_DATA;
|
||||
/* We could also check whole padding but we do not really need this */
|
||||
|
||||
memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
|
||||
return AES_BLOCK_SIZE*num_blocks - pad_len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get size of buffer which will be large enough for encrypted data
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_get_size()
|
||||
source_length Length of data to be encrypted
|
||||
|
||||
RETURN
|
||||
Size of buffer required to store encrypted data
|
||||
*/
|
||||
|
||||
int my_aes_get_size(int source_length)
|
||||
{
|
||||
return AES_BLOCK_SIZE*(source_length/AES_BLOCK_SIZE)+AES_BLOCK_SIZE;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Function to set a varible when we got a alarm */
|
||||
/* Used by my_lock samt functions in m_alarm.h */
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_alarm.h"
|
||||
|
||||
#ifdef HAVE_ALARM
|
||||
|
||||
/* ARGSUSED */
|
||||
sig_handler my_set_alarm_variable(int signo __attribute__((unused)))
|
||||
{
|
||||
my_have_got_alarm=1; /* Tell program that time expired */
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* HAVE_ALARM */
|
||||
@@ -120,7 +120,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
|
||||
{
|
||||
/* remove block from the list and free it */
|
||||
*prev= mem->next;
|
||||
my_free(mem, MYF(0));
|
||||
my_free(mem);
|
||||
}
|
||||
else
|
||||
prev= &mem->next;
|
||||
@@ -163,7 +163,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
|
||||
});
|
||||
|
||||
length+=ALIGN_SIZE(sizeof(USED_MEM));
|
||||
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME))))
|
||||
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
|
||||
{
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
@@ -214,7 +214,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length)
|
||||
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
|
||||
get_size= max(get_size, block_size);
|
||||
|
||||
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
|
||||
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
|
||||
{
|
||||
if (mem_root->error_handler)
|
||||
(*mem_root->error_handler)();
|
||||
@@ -362,13 +362,13 @@ void free_root(MEM_ROOT *root, myf MyFlags)
|
||||
{
|
||||
old=next; next= next->next ;
|
||||
if (old != root->pre_alloc)
|
||||
my_free(old,MYF(0));
|
||||
my_free(old);
|
||||
}
|
||||
for (next=root->free ; next ;)
|
||||
{
|
||||
old=next; next= next->next;
|
||||
if (old != root->pre_alloc)
|
||||
my_free(old,MYF(0));
|
||||
my_free(old);
|
||||
}
|
||||
root->used=root->free=0;
|
||||
if (root->pre_alloc)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include <my_atomic.h>
|
||||
|
||||
/*
|
||||
checks that the current build of atomic ops
|
||||
can run on this machine
|
||||
|
||||
RETURN
|
||||
ATOMIC_xxx values, see my_atomic.h
|
||||
*/
|
||||
int my_atomic_initialize()
|
||||
{
|
||||
compile_time_assert(sizeof(intptr) == sizeof(void *));
|
||||
/* currently the only thing worth checking is SMP/UP issue */
|
||||
#ifdef MY_ATOMIC_MODE_DUMMY
|
||||
return my_getncpus() == 1 ? MY_ATOMIC_OK : MY_ATOMIC_NOT_1CPU;
|
||||
#else
|
||||
return MY_ATOMIC_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SAFE_MUTEX
|
||||
#undef pthread_mutex_init
|
||||
#undef pthread_mutex_destroy
|
||||
#undef pthread_mutex_lock
|
||||
#undef pthread_mutex_unlock
|
||||
|
||||
void plain_pthread_mutex_init(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_init(& m->mutex, NULL);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_destroy(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_destroy(& m->mutex);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_lock(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_lock(& m->mutex);
|
||||
}
|
||||
|
||||
void plain_pthread_mutex_unlock(safe_mutex_t *m)
|
||||
{
|
||||
pthread_mutex_unlock(& m->mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#include <my_bit.h>
|
||||
|
||||
const char _my_bits_nbits[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
|
||||
};
|
||||
|
||||
/*
|
||||
perl -e 'print map{", 0x".unpack H2,pack B8,unpack b8,chr$_}(0..255)'
|
||||
*/
|
||||
const uchar _my_bits_reverse_table[256]={
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30,
|
||||
0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98,
|
||||
0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64,
|
||||
0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC,
|
||||
0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02,
|
||||
0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2,
|
||||
0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A,
|
||||
0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
||||
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E,
|
||||
0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81,
|
||||
0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71,
|
||||
0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
|
||||
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15,
|
||||
0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD,
|
||||
0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43,
|
||||
0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
||||
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B,
|
||||
0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97,
|
||||
0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F,
|
||||
0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
|
||||
};
|
||||
|
||||
@@ -0,0 +1,932 @@
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Handling of uchar arrays as large bitmaps.
|
||||
|
||||
API limitations (or, rather asserted safety assumptions,
|
||||
to encourage correct programming)
|
||||
|
||||
* the internal size is a set of 32 bit words
|
||||
* the number of bits specified in creation can be any number > 0
|
||||
* there are THREAD safe versions of most calls called bitmap_lock_*
|
||||
|
||||
TODO:
|
||||
Make assembler THREAD safe versions of these using test-and-set instructions
|
||||
|
||||
Original version created by Sergei Golubchik 2001 - 2004.
|
||||
New version written and test program added and some changes to the interface
|
||||
was made by Mikael Ronström 2005, with assistance of Tomas Ulin and Mats
|
||||
Kindahl.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_bitmap.h>
|
||||
#include <m_string.h>
|
||||
#include <my_bit.h>
|
||||
|
||||
void create_last_word_mask(MY_BITMAP *map)
|
||||
{
|
||||
/* Get the number of used bits (1..8) in the last byte */
|
||||
unsigned int const used= 1U + ((map->n_bits-1U) & 0x7U);
|
||||
|
||||
/*
|
||||
Create a mask with the upper 'unused' bits set and the lower 'used'
|
||||
bits clear. The bits within each byte is stored in big-endian order.
|
||||
*/
|
||||
unsigned char const mask= (~((1 << used) - 1)) & 255;
|
||||
|
||||
/*
|
||||
The first bytes are to be set to zero since they represent real bits
|
||||
in the bitvector. The last bytes are set to 0xFF since they represent
|
||||
bytes not used by the bitvector. Finally the last byte contains bits
|
||||
as set by the mask above.
|
||||
*/
|
||||
unsigned char *ptr= (unsigned char*)&map->last_word_mask;
|
||||
|
||||
map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
|
||||
switch (no_bytes_in_map(map) & 3) {
|
||||
case 1:
|
||||
map->last_word_mask= ~0U;
|
||||
ptr[0]= mask;
|
||||
return;
|
||||
case 2:
|
||||
map->last_word_mask= ~0U;
|
||||
ptr[0]= 0;
|
||||
ptr[1]= mask;
|
||||
return;
|
||||
case 3:
|
||||
map->last_word_mask= 0U;
|
||||
ptr[2]= mask;
|
||||
ptr[3]= 0xFFU;
|
||||
return;
|
||||
case 0:
|
||||
map->last_word_mask= 0U;
|
||||
ptr[3]= mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused)))
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_lock(map->mutex);
|
||||
}
|
||||
|
||||
static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_unlock(map->mutex);
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
|
||||
my_bool thread_safe __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("bitmap_init");
|
||||
if (!buf)
|
||||
{
|
||||
uint size_in_bytes= bitmap_buffer_size(n_bits);
|
||||
uint extra= 0;
|
||||
|
||||
if (thread_safe)
|
||||
{
|
||||
size_in_bytes= ALIGN_SIZE(size_in_bytes);
|
||||
extra= sizeof(mysql_mutex_t);
|
||||
}
|
||||
map->mutex= 0;
|
||||
|
||||
if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (thread_safe)
|
||||
{
|
||||
map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes);
|
||||
mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(thread_safe == 0);
|
||||
}
|
||||
|
||||
|
||||
map->bitmap= buf;
|
||||
map->n_bits= n_bits;
|
||||
create_last_word_mask(map);
|
||||
bitmap_clear_all(map);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void bitmap_free(MY_BITMAP *map)
|
||||
{
|
||||
DBUG_ENTER("bitmap_free");
|
||||
if (map->bitmap)
|
||||
{
|
||||
if (map->mutex)
|
||||
mysql_mutex_destroy(map->mutex);
|
||||
|
||||
my_free(map->bitmap);
|
||||
map->bitmap=0;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test if bit already set and set it if it was not (thread unsafe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
MAP bit map struct
|
||||
BIT bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
|
||||
uchar bit= 1 << ((bitmap_bit) & 7);
|
||||
uchar res= (*value) & bit;
|
||||
*value|= bit;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
test if bit already set and set it if it was not (thread safe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
map bit map struct
|
||||
bitmap_bit bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
my_bool res;
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_lock(map);
|
||||
res= bitmap_fast_test_and_set(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
test if bit already set and clear it if it was set(thread unsafe method)
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_fast_test_and_set()
|
||||
MAP bit map struct
|
||||
BIT bit number
|
||||
|
||||
RETURN
|
||||
0 bit was not set
|
||||
!=0 bit was set
|
||||
*/
|
||||
|
||||
my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
|
||||
uchar bit= 1 << ((bitmap_bit) & 7);
|
||||
uchar res= (*byte) & bit;
|
||||
*byte&= ~bit;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
my_bool res;
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_lock(map);
|
||||
res= bitmap_fast_test_and_clear(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_set_next(MY_BITMAP *map)
|
||||
{
|
||||
uint bit_found;
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
if ((bit_found= bitmap_get_first(map)) != MY_BIT_NONE)
|
||||
bitmap_set_bit(map, bit_found);
|
||||
return bit_found;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
uint prefix_bytes, prefix_bits, d;
|
||||
uchar *m= (uchar *)map->bitmap;
|
||||
|
||||
DBUG_ASSERT(map->bitmap &&
|
||||
(prefix_size <= map->n_bits || prefix_size == (uint) ~0));
|
||||
set_if_smaller(prefix_size, map->n_bits);
|
||||
if ((prefix_bytes= prefix_size / 8))
|
||||
memset(m, 0xff, prefix_bytes);
|
||||
m+= prefix_bytes;
|
||||
if ((prefix_bits= prefix_size & 7))
|
||||
*m++= (1 << prefix_bits)-1;
|
||||
if ((d= no_bytes_in_map(map)-prefix_bytes))
|
||||
bzero(m, d);
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
|
||||
{
|
||||
uint prefix_bits= prefix_size & 0x7, res;
|
||||
uchar *m= (uchar*)map->bitmap;
|
||||
uchar *end_prefix= m+prefix_size/8;
|
||||
uchar *end;
|
||||
DBUG_ASSERT(m && prefix_size <= map->n_bits);
|
||||
end= m+no_bytes_in_map(map);
|
||||
|
||||
while (m < end_prefix)
|
||||
if (*m++ != 0xff)
|
||||
return 0;
|
||||
|
||||
*map->last_word_ptr&= ~map->last_word_mask; /*Clear bits*/
|
||||
res= 0;
|
||||
if (prefix_bits && *m++ != (1 << prefix_bits)-1)
|
||||
goto ret;
|
||||
|
||||
while (m < end)
|
||||
if (*m++ != 0)
|
||||
goto ret;
|
||||
res= 1;
|
||||
ret:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_set_all(const MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *data_ptr= map->bitmap;
|
||||
my_bitmap_map *end= map->last_word_ptr;
|
||||
*map->last_word_ptr |= map->last_word_mask;
|
||||
for (; data_ptr <= end; data_ptr++)
|
||||
if (*data_ptr != 0xFFFFFFFF)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *data_ptr= map->bitmap;
|
||||
my_bitmap_map *end;
|
||||
if (*map->last_word_ptr & ~map->last_word_mask)
|
||||
return FALSE;
|
||||
end= map->last_word_ptr;
|
||||
for (; data_ptr < end; data_ptr++)
|
||||
if (*data_ptr)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return TRUE if map1 is a subset of map2 */
|
||||
|
||||
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
||||
map1->n_bits==map2->n_bits);
|
||||
|
||||
end= map1->last_word_ptr;
|
||||
*map1->last_word_ptr &= ~map1->last_word_mask;
|
||||
*map2->last_word_ptr &= ~map2->last_word_mask;
|
||||
while (m1 <= end)
|
||||
{
|
||||
if ((*m1++) & ~(*m2++))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* True if bitmaps has any common bits */
|
||||
|
||||
my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
|
||||
map1->n_bits==map2->n_bits);
|
||||
|
||||
end= map1->last_word_ptr;
|
||||
*map1->last_word_ptr &= ~map1->last_word_mask;
|
||||
*map2->last_word_ptr &= ~map2->last_word_mask;
|
||||
while (m1 <= end)
|
||||
{
|
||||
if ((*m1++) & (*m2++))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap);
|
||||
|
||||
end= to+min(len,len2);
|
||||
*map2->last_word_ptr&= ~map2->last_word_mask; /*Clear last bits in map2*/
|
||||
while (to < end)
|
||||
*to++ &= *from++;
|
||||
|
||||
if (len2 < len)
|
||||
{
|
||||
end+=len-len2;
|
||||
while (to < end)
|
||||
*to++=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set/clear all bits above a bit.
|
||||
|
||||
SYNOPSIS
|
||||
bitmap_set_above()
|
||||
map RETURN The bitmap to change.
|
||||
from_byte The bitmap buffer byte offset to start with.
|
||||
use_bit The bit value (1/0) to use for all upper bits.
|
||||
|
||||
NOTE
|
||||
You can only set/clear full bytes.
|
||||
The function is meant for the situation that you copy a smaller bitmap
|
||||
to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
|
||||
size of a byte). Using 'from_byte' saves multiplication and division
|
||||
by eight during parameter passing.
|
||||
|
||||
RETURN
|
||||
void
|
||||
*/
|
||||
|
||||
void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
|
||||
{
|
||||
uchar use_byte= use_bit ? 0xff : 0;
|
||||
uchar *to= (uchar *)map->bitmap + from_byte;
|
||||
uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
|
||||
|
||||
while (to < end)
|
||||
*to++= use_byte;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ &= ~(*from++);
|
||||
}
|
||||
|
||||
|
||||
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ |= *from++;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
while (to <= end)
|
||||
*to++ ^= *from++;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_invert(MY_BITMAP *map)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
end= map->last_word_ptr;
|
||||
|
||||
while (to <= end)
|
||||
*to++ ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_bits_set(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *m= (uchar*)map->bitmap;
|
||||
uchar *end= m + no_bytes_in_map(map);
|
||||
uint res= 0;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
*map->last_word_ptr&= ~map->last_word_mask; /*Reset last bits to zero*/
|
||||
while (m < end)
|
||||
res+= my_count_bits_ushort(*m++);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
|
||||
{
|
||||
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
|
||||
|
||||
DBUG_ASSERT(map->bitmap && map2->bitmap &&
|
||||
map->n_bits==map2->n_bits);
|
||||
end= map->last_word_ptr;
|
||||
while (to <= end)
|
||||
*to++ = *from++;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_get_first_set(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *byte_ptr;
|
||||
uint i,j,k;
|
||||
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
data_ptr= map->bitmap;
|
||||
*map->last_word_ptr &= ~map->last_word_mask;
|
||||
|
||||
for (i=0; data_ptr <= end; data_ptr++, i++)
|
||||
{
|
||||
if (*data_ptr)
|
||||
{
|
||||
byte_ptr= (uchar*)data_ptr;
|
||||
for (j=0; ; j++, byte_ptr++)
|
||||
{
|
||||
if (*byte_ptr)
|
||||
{
|
||||
for (k=0; ; k++)
|
||||
{
|
||||
if (*byte_ptr & (1 << k))
|
||||
return (i*32) + (j*8) + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MY_BIT_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_get_first(const MY_BITMAP *map)
|
||||
{
|
||||
uchar *byte_ptr;
|
||||
uint i,j,k;
|
||||
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
|
||||
|
||||
DBUG_ASSERT(map->bitmap);
|
||||
data_ptr= map->bitmap;
|
||||
*map->last_word_ptr|= map->last_word_mask;
|
||||
|
||||
for (i=0; data_ptr <= end; data_ptr++, i++)
|
||||
{
|
||||
if (*data_ptr != 0xFFFFFFFF)
|
||||
{
|
||||
byte_ptr= (uchar*)data_ptr;
|
||||
for (j=0; ; j++, byte_ptr++)
|
||||
{
|
||||
if (*byte_ptr != 0xFF)
|
||||
{
|
||||
for (k=0; ; k++)
|
||||
{
|
||||
if (!(*byte_ptr & (1 << k)))
|
||||
return (i*32) + (j*8) + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MY_BIT_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint bitmap_lock_set_next(MY_BITMAP *map)
|
||||
{
|
||||
uint bit_found;
|
||||
bitmap_lock(map);
|
||||
bit_found= bitmap_set_next(map);
|
||||
bitmap_unlock(map);
|
||||
return bit_found;
|
||||
}
|
||||
|
||||
|
||||
void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
|
||||
{
|
||||
bitmap_lock(map);
|
||||
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
|
||||
bitmap_clear_bit(map, bitmap_bit);
|
||||
bitmap_unlock(map);
|
||||
}
|
||||
|
||||
#ifdef MAIN
|
||||
|
||||
uint get_rand_bit(uint bitsize)
|
||||
{
|
||||
return (rand() % bitsize);
|
||||
}
|
||||
|
||||
bool test_set_get_clear_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit= get_rand_bit(bitsize);
|
||||
bitmap_set_bit(map, test_bit);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_bit(map, test_bit);
|
||||
if (bitmap_is_set(map, test_bit))
|
||||
goto error2;
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_flip_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit= get_rand_bit(bitsize);
|
||||
bitmap_flip_bit(map, test_bit);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_flip_bit(map, test_bit);
|
||||
if (bitmap_is_set(map, test_bit))
|
||||
goto error2;
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_operators(MY_BITMAP *map __attribute__((unused)),
|
||||
uint bitsize __attribute__((unused)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool test_get_all_bits(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i;
|
||||
bitmap_set_all(map);
|
||||
if (!bitmap_is_set_all(map))
|
||||
goto error1;
|
||||
if (!bitmap_is_prefix(map, bitsize))
|
||||
goto error5;
|
||||
bitmap_clear_all(map);
|
||||
if (!bitmap_is_clear_all(map))
|
||||
goto error2;
|
||||
if (!bitmap_is_prefix(map, 0))
|
||||
goto error6;
|
||||
for (i=0; i<bitsize;i++)
|
||||
bitmap_set_bit(map, i);
|
||||
if (!bitmap_is_set_all(map))
|
||||
goto error3;
|
||||
for (i=0; i<bitsize;i++)
|
||||
bitmap_clear_bit(map, i);
|
||||
if (!bitmap_is_clear_all(map))
|
||||
goto error4;
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("Error in set_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Error in clear_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("Error in bitmap_is_set_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error4:
|
||||
printf("Error in bitmap_is_clear_all, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error5:
|
||||
printf("Error in set_all through set_prefix, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error6:
|
||||
printf("Error in clear_all through set_prefix, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_compare_operators(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit1, test_bit2, test_bit3,test_bit4;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
MY_BITMAP map2_obj, map3_obj;
|
||||
MY_BITMAP *map2= &map2_obj, *map3= &map3_obj;
|
||||
my_bitmap_map map2buf[1024];
|
||||
my_bitmap_map map3buf[1024];
|
||||
bitmap_init(&map2_obj, map2buf, bitsize, FALSE);
|
||||
bitmap_init(&map3_obj, map3buf, bitsize, FALSE);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_intersect(map, map2);
|
||||
test_bit3= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
bitmap_union(map, map2);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error2;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_xor(map, map2);
|
||||
test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1;
|
||||
test_bit4= test_bit2 < test_bit1 ? test_bit2 : test_bit1;
|
||||
bitmap_set_prefix(map3, test_bit3);
|
||||
for (j=0; j < test_bit4; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error3;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
test_bit2=get_rand_bit(bitsize);
|
||||
test_bit3=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_set_prefix(map2, test_bit2);
|
||||
bitmap_subtract(map, map2);
|
||||
if (test_bit2 < test_bit1)
|
||||
{
|
||||
bitmap_set_prefix(map3, test_bit1);
|
||||
for (j=0; j < test_bit2; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
}
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error4;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map2);
|
||||
bitmap_clear_all(map3);
|
||||
test_bit1=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit1);
|
||||
bitmap_invert(map);
|
||||
bitmap_set_all(map3);
|
||||
for (j=0; j < test_bit1; j++)
|
||||
bitmap_clear_bit(map3, j);
|
||||
if (!bitmap_cmp(map, map3))
|
||||
goto error5;
|
||||
bitmap_clear_all(map);
|
||||
bitmap_clear_all(map3);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("intersect error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("union error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("xor error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error4:
|
||||
printf("subtract error bitsize=%u,size1=%u,size2=%u", bitsize,
|
||||
test_bit1,test_bit2);
|
||||
return TRUE;
|
||||
error5:
|
||||
printf("invert error bitsize=%u,size=%u", bitsize,
|
||||
test_bit1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_count_bits_set(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, bit_count=0, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
if (!bitmap_is_set(map, test_bit))
|
||||
{
|
||||
bitmap_set_bit(map, test_bit);
|
||||
bit_count++;
|
||||
}
|
||||
}
|
||||
if (bit_count==0 && bitsize > 0)
|
||||
goto error1;
|
||||
if (bitmap_bits_set(map) != bit_count)
|
||||
goto error2;
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("No bits set bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("Wrong count of bits set, bitsize = %u", bitsize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_get_first_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
bitmap_set_bit(map, test_bit);
|
||||
if (bitmap_get_first_set(map) != test_bit)
|
||||
goto error1;
|
||||
bitmap_set_all(map);
|
||||
bitmap_clear_bit(map, test_bit);
|
||||
if (bitmap_get_first(map) != test_bit)
|
||||
goto error2;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("get_first_set error bitsize=%u,prefix_size=%u",bitsize,test_bit);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("get_first error bitsize= %u, prefix_size= %u",bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_get_next_bit(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
for (j=0; j < test_bit; j++)
|
||||
bitmap_set_next(map);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("get_next error bitsize= %u, prefix_size= %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool test_prefix(MY_BITMAP *map, uint bitsize)
|
||||
{
|
||||
uint i, j, test_bit;
|
||||
uint no_loops= bitsize > 128 ? 128 : bitsize;
|
||||
for (i=0; i < no_loops; i++)
|
||||
{
|
||||
test_bit=get_rand_bit(bitsize);
|
||||
bitmap_set_prefix(map, test_bit);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error1;
|
||||
bitmap_clear_all(map);
|
||||
for (j=0; j < test_bit; j++)
|
||||
bitmap_set_bit(map, j);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error2;
|
||||
bitmap_set_all(map);
|
||||
for (j=bitsize - 1; ~(j-test_bit); j--)
|
||||
bitmap_clear_bit(map, j);
|
||||
if (!bitmap_is_prefix(map, test_bit))
|
||||
goto error3;
|
||||
bitmap_clear_all(map);
|
||||
}
|
||||
return FALSE;
|
||||
error1:
|
||||
printf("prefix1 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
error2:
|
||||
printf("prefix2 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
error3:
|
||||
printf("prefix3 error bitsize = %u, prefix_size = %u", bitsize,test_bit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool do_test(uint bitsize)
|
||||
{
|
||||
MY_BITMAP map;
|
||||
my_bitmap_map buf[1024];
|
||||
if (bitmap_init(&map, buf, bitsize, FALSE))
|
||||
{
|
||||
printf("init error for bitsize %d", bitsize);
|
||||
goto error;
|
||||
}
|
||||
if (test_set_get_clear_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_flip_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_operators(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_all_bits(&map, bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_compare_operators(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_count_bits_set(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_first_bit(&map,bitsize))
|
||||
goto error;
|
||||
bitmap_clear_all(&map);
|
||||
if (test_get_next_bit(&map,bitsize))
|
||||
goto error;
|
||||
if (test_prefix(&map,bitsize))
|
||||
goto error;
|
||||
return FALSE;
|
||||
error:
|
||||
printf("\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
for (i= 1; i < 4096; i++)
|
||||
{
|
||||
printf("Start test for bitsize=%u\n",i);
|
||||
if (do_test(i))
|
||||
return -1;
|
||||
}
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
In directory mysys:
|
||||
make test_bitmap
|
||||
will build the bitmap tests and ./test_bitmap will execute it
|
||||
*/
|
||||
|
||||
#endif
|
||||
@@ -52,20 +52,13 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
|
||||
|
||||
if (oldsize > newlength)
|
||||
{
|
||||
#if defined(HAVE_SETFILEPOINTER)
|
||||
/* This is for the moment only true on windows */
|
||||
long is_success;
|
||||
HANDLE win_file= (HANDLE) _get_osfhandle(fd);
|
||||
long length_low, length_high;
|
||||
length_low= (long) (ulong) newlength;
|
||||
length_high= (long) ((ulonglong) newlength >> 32);
|
||||
is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN);
|
||||
if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR)
|
||||
#ifdef _WIN32
|
||||
if (my_win_chsize(fd, newlength))
|
||||
{
|
||||
my_errno= errno;
|
||||
goto err;
|
||||
if (SetEndOfFile(win_file))
|
||||
DBUG_RETURN(0);
|
||||
my_errno= GetLastError();
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
#elif defined(HAVE_FTRUNCATE)
|
||||
if (ftruncate(fd, (off_t) newlength))
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
|
||||
if (!compbuf)
|
||||
DBUG_RETURN(*complen ? 0 : 1);
|
||||
memcpy(packet,compbuf,*len);
|
||||
my_free(compbuf,MYF(MY_WME));
|
||||
my_free(compbuf);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -73,14 +73,14 @@ uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
|
||||
|
||||
if (res != Z_OK)
|
||||
{
|
||||
my_free(compbuf, MYF(MY_WME));
|
||||
my_free(compbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*complen >= *len)
|
||||
{
|
||||
*complen= 0;
|
||||
my_free(compbuf, MYF(MY_WME));
|
||||
my_free(compbuf);
|
||||
DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
|
||||
return 0;
|
||||
}
|
||||
@@ -125,11 +125,11 @@ my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
|
||||
if (error != Z_OK)
|
||||
{ /* Probably wrong packet */
|
||||
DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
|
||||
my_free(compbuf, MYF(MY_WME));
|
||||
my_free(compbuf);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
memcpy(packet, compbuf, *complen);
|
||||
my_free(compbuf, MYF(MY_WME));
|
||||
my_free(compbuf);
|
||||
}
|
||||
else
|
||||
*complen= len;
|
||||
@@ -250,7 +250,7 @@ int unpackfrm(uchar **unpack_data, size_t *unpack_len,
|
||||
|
||||
if (my_uncompress(data, complen, &orglen))
|
||||
{
|
||||
my_free(data, MYF(0));
|
||||
my_free(data);
|
||||
DBUG_RETURN(3);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
static HANDLE my_coninpfh= 0; /* console input */
|
||||
|
||||
/*
|
||||
functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free
|
||||
are experimental at this moment, they are intended to bring
|
||||
ability of protecting code sections without necessity to explicitly
|
||||
initialize synchronization object in one of threads
|
||||
|
||||
if found useful they are to be exported in mysys
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name,
|
||||
int id, int time)
|
||||
NOTES
|
||||
creates a mutex with given name and tries to lock it time msec.
|
||||
mutex name is appended with id to allow system wide or process wide
|
||||
locks. Handle to created mutex returned in ph argument.
|
||||
|
||||
RETURN
|
||||
0 thread owns mutex
|
||||
<>0 error
|
||||
*/
|
||||
|
||||
static
|
||||
int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time)
|
||||
{
|
||||
int res;
|
||||
char tname[FN_REFLEN];
|
||||
|
||||
sprintf(tname, "%s-%08X", name, id);
|
||||
|
||||
*ph= CreateMutex(NULL, FALSE, tname);
|
||||
if (*ph == NULL)
|
||||
return GetLastError();
|
||||
|
||||
res= WaitForSingleObject(*ph, time);
|
||||
|
||||
if (res == WAIT_TIMEOUT)
|
||||
return ERROR_SEM_TIMEOUT;
|
||||
|
||||
if (res == WAIT_FAILED)
|
||||
return GetLastError();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int my_pthread_auto_mutex_free(HANDLE* ph)
|
||||
|
||||
NOTES
|
||||
releases a mutex.
|
||||
|
||||
RETURN
|
||||
0 thread released mutex
|
||||
<>0 error
|
||||
|
||||
*/
|
||||
static
|
||||
int my_pthread_auto_mutex_free(HANDLE* ph)
|
||||
{
|
||||
if (*ph)
|
||||
{
|
||||
ReleaseMutex(*ph);
|
||||
CloseHandle(*ph);
|
||||
*ph= NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define pthread_auto_mutex_decl(name) \
|
||||
HANDLE __h##name= NULL;
|
||||
|
||||
#define pthread_auto_mutex_lock(name, proc, time) \
|
||||
my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time))
|
||||
|
||||
#define pthread_auto_mutex_free(name) \
|
||||
my_pthread_auto_mutex_free(&__h##name)
|
||||
|
||||
|
||||
/*
|
||||
char* my_cgets()
|
||||
|
||||
NOTES
|
||||
Replaces _cgets from libc to support input of more than 255 chars.
|
||||
Reads from the console via ReadConsole into buffer which
|
||||
should be at least clen characters.
|
||||
Actual length of string returned in plen.
|
||||
|
||||
WARNING
|
||||
my_cgets() does NOT check the pushback character buffer (i.e., _chbuf).
|
||||
Thus, my_cgets() will not return any character that is pushed back by
|
||||
the _ungetch() call.
|
||||
|
||||
RETURN
|
||||
string pointer ok
|
||||
NULL Error
|
||||
|
||||
*/
|
||||
|
||||
char* my_cgets(char *buffer, size_t clen, size_t* plen)
|
||||
{
|
||||
ULONG state;
|
||||
char *result;
|
||||
DWORD plen_res;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
pthread_auto_mutex_decl(my_conio_cs);
|
||||
|
||||
/* lock the console for the current process*/
|
||||
if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE))
|
||||
{
|
||||
/* can not lock console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init console input */
|
||||
if (my_coninpfh == 0)
|
||||
{
|
||||
/* same handle will be used until process termination */
|
||||
my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
}
|
||||
|
||||
if (my_coninpfh == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* unlock the console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
GetConsoleMode((HANDLE)my_coninpfh, &state);
|
||||
SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT |
|
||||
ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
|
||||
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
||||
|
||||
/*
|
||||
there is no known way to determine allowed buffer size for input
|
||||
though it is known it should not be more than 64K
|
||||
so we cut 64K and try first size of screen buffer
|
||||
if it is still to large we cut half of it and try again
|
||||
later we may want to cycle from min(clen, 65535) to allowed size
|
||||
with small decrement to determine exact allowed buffer
|
||||
*/
|
||||
clen= min(clen, 65535);
|
||||
do
|
||||
{
|
||||
clen= min(clen, (size_t) csbi.dwSize.X*csbi.dwSize.Y);
|
||||
if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, (DWORD) clen - 1, &plen_res,
|
||||
NULL))
|
||||
{
|
||||
result= NULL;
|
||||
clen>>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result= buffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY);
|
||||
*plen= plen_res;
|
||||
|
||||
/* We go here on error reading the string (Ctrl-C for example) */
|
||||
if (!*plen)
|
||||
result= NULL; /* purecov: inspected */
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
if (*plen > 1 && buffer[*plen - 2] == '\r')
|
||||
{
|
||||
*plen= *plen - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*plen > 0 && buffer[*plen - 1] == '\r')
|
||||
{
|
||||
char tmp[3];
|
||||
int tmplen= sizeof(tmp);
|
||||
|
||||
*plen= *plen - 1;
|
||||
/* read /n left in the buffer */
|
||||
ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL);
|
||||
}
|
||||
}
|
||||
buffer[*plen]= '\0';
|
||||
}
|
||||
|
||||
SetConsoleMode((HANDLE)my_coninpfh, state);
|
||||
/* unlock the console */
|
||||
pthread_auto_mutex_free(my_conio_cs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __WIN__ */
|
||||
@@ -0,0 +1,144 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h> /* for stat */
|
||||
#include <m_string.h>
|
||||
#include "mysys_err.h"
|
||||
#if defined(HAVE_UTIME_H)
|
||||
#include <utime.h>
|
||||
#elif defined(HAVE_SYS_UTIME_H)
|
||||
#include <sys/utime.h>
|
||||
#elif !defined(HPUX10)
|
||||
#include <time.h>
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
int my_copy(const char *from, const char *to, myf MyFlags)
|
||||
|
||||
NOTES
|
||||
Ordinary ownership and accesstimes are copied from 'from-file'
|
||||
If MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
|
||||
the modes of to-file isn't changed
|
||||
If MyFlags & MY_DONT_OVERWRITE_FILE is set, we will give an error
|
||||
if the file existed.
|
||||
|
||||
WARNING
|
||||
Don't set MY_FNABP or MY_NABP bits on when calling this function !
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
# Error
|
||||
|
||||
*/
|
||||
|
||||
int my_copy(const char *from, const char *to, myf MyFlags)
|
||||
{
|
||||
size_t Count;
|
||||
my_bool new_file_stat= 0; /* 1 if we could stat "to" */
|
||||
int create_flag;
|
||||
File from_file,to_file;
|
||||
uchar buff[IO_SIZE];
|
||||
MY_STAT stat_buff,new_stat_buff;
|
||||
DBUG_ENTER("my_copy");
|
||||
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
|
||||
|
||||
from_file=to_file= -1;
|
||||
DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
|
||||
new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0)));
|
||||
|
||||
if ((from_file=my_open(from,O_RDONLY | O_SHARE,MyFlags)) >= 0)
|
||||
{
|
||||
if (!my_stat(from, &stat_buff, MyFlags))
|
||||
{
|
||||
my_errno=errno;
|
||||
goto err;
|
||||
}
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
|
||||
stat_buff=new_stat_buff;
|
||||
create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC;
|
||||
|
||||
if ((to_file= my_create(to,(int) stat_buff.st_mode,
|
||||
O_WRONLY | create_flag | O_BINARY | O_SHARE,
|
||||
MyFlags)) < 0)
|
||||
goto err;
|
||||
|
||||
while ((Count=my_read(from_file, buff, sizeof(buff), MyFlags)) != 0)
|
||||
{
|
||||
if (Count == (uint) -1 ||
|
||||
my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* sync the destination file */
|
||||
if (MyFlags & MY_SYNC)
|
||||
{
|
||||
if (my_sync(to_file, MyFlags))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
|
||||
DBUG_RETURN(-1); /* Error on close */
|
||||
|
||||
/* Copy modes if possible */
|
||||
|
||||
if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
|
||||
DBUG_RETURN(0); /* File copyed but not stat */
|
||||
/* Copy modes */
|
||||
if (chmod(to, stat_buff.st_mode & 07777))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
goto err;
|
||||
}
|
||||
#if !defined(__WIN__)
|
||||
/* Copy ownership */
|
||||
if (chown(to, stat_buff.st_uid, stat_buff.st_gid))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MyFlags & MY_COPYTIME)
|
||||
{
|
||||
struct utimbuf timep;
|
||||
timep.actime = stat_buff.st_atime;
|
||||
timep.modtime = stat_buff.st_mtime;
|
||||
(void) utime((char*) to, &timep); /* last accessed and modified times */
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
err:
|
||||
if (from_file >= 0) (void) my_close(from_file,MyFlags);
|
||||
if (to_file >= 0)
|
||||
{
|
||||
(void) my_close(to_file, MyFlags);
|
||||
/* attempt to delete the to-file we've partially written */
|
||||
(void) my_delete(to, MyFlags);
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
} /* my_copy */
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#include <my_sys.h>
|
||||
#if defined(__WIN__)
|
||||
#if defined(_WIN32)
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
@@ -39,18 +39,11 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
|
||||
DBUG_ENTER("my_create");
|
||||
DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
|
||||
FileName, CreateFlags, access_flags, MyFlags));
|
||||
|
||||
#if !defined(NO_OPEN_3)
|
||||
fd = open((char *) FileName, access_flags | O_CREAT,
|
||||
CreateFlags ? CreateFlags : my_umask);
|
||||
#elif defined(VMS)
|
||||
fd = open((char *) FileName, access_flags | O_CREAT, 0,
|
||||
"ctx=stm","ctx=bin");
|
||||
#elif defined(__WIN__)
|
||||
fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY,
|
||||
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
|
||||
#if defined(_WIN32)
|
||||
fd= my_win_open(FileName, access_flags | O_CREAT);
|
||||
#else
|
||||
fd = open(FileName, access_flags);
|
||||
fd= open((char *) FileName, access_flags | O_CREAT,
|
||||
CreateFlags ? CreateFlags : my_umask);
|
||||
#endif
|
||||
|
||||
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
|
||||
@@ -71,6 +64,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
|
||||
if (unlikely(fd >= 0 && rc < 0))
|
||||
{
|
||||
int tmp= my_errno;
|
||||
my_close(fd, MyFlags);
|
||||
my_delete(FileName, MyFlags);
|
||||
my_errno= tmp;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ int my_delete(const char *name, myf MyFlags)
|
||||
DBUG_RETURN(err);
|
||||
} /* my_delete */
|
||||
|
||||
#if defined(__WIN__) && defined(__NT__)
|
||||
/*
|
||||
#if defined(__WIN__)
|
||||
/**
|
||||
Delete file which is possibly not closed.
|
||||
|
||||
This function is intended to be used exclusively as a temporal solution
|
||||
@@ -53,6 +53,20 @@ int my_delete(const char *name, myf MyFlags)
|
||||
renamed to <name>.<num>.deleted where <name> - the initial name of the
|
||||
file, <num> - a hexadecimal number chosen to make the temporal name to
|
||||
be unique.
|
||||
|
||||
@param the name of the being deleted file
|
||||
@param the flags instructing how to react on an error internally in
|
||||
the function
|
||||
|
||||
@note The per-thread @c my_errno holds additional info for a caller to
|
||||
decide how critical the error can be.
|
||||
|
||||
@retval
|
||||
0 ok
|
||||
@retval
|
||||
1 error
|
||||
|
||||
|
||||
*/
|
||||
int nt_share_delete(const char *name, myf MyFlags)
|
||||
{
|
||||
@@ -63,6 +77,7 @@ int nt_share_delete(const char *name, myf MyFlags)
|
||||
|
||||
for (cnt= GetTickCount(); cnt; cnt--)
|
||||
{
|
||||
errno= 0;
|
||||
sprintf(buf, "%s.%08X.deleted", name, cnt);
|
||||
if (MoveFile(name, buf))
|
||||
break;
|
||||
@@ -79,14 +94,32 @@ int nt_share_delete(const char *name, myf MyFlags)
|
||||
break;
|
||||
}
|
||||
|
||||
if (DeleteFile(buf))
|
||||
DBUG_RETURN(0);
|
||||
if (errno == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
my_errno= ENOENT; // marking, that `name' doesn't exist
|
||||
}
|
||||
else if (errno == 0)
|
||||
{
|
||||
if (DeleteFile(buf))
|
||||
DBUG_RETURN(0);
|
||||
/*
|
||||
The below is more complicated than necessary. For some reason, the
|
||||
assignment to my_errno clears the error number, which is retrieved
|
||||
by GetLastError() (VC2005EE). Assigning to errno first, allows to
|
||||
retrieve the correct value.
|
||||
*/
|
||||
errno= GetLastError();
|
||||
if (errno == 0)
|
||||
my_errno= ENOENT; // marking, that `buf' doesn't exist
|
||||
else
|
||||
my_errno= errno;
|
||||
}
|
||||
else
|
||||
my_errno= errno;
|
||||
|
||||
my_errno= GetLastError();
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_DELETE, MYF(ME_BELL + ME_WAITTANG + (MyFlags & ME_NOINPUT)),
|
||||
name, my_errno);
|
||||
|
||||
name, my_errno);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
/* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */
|
||||
#define ERRMSGSIZE (512)
|
||||
|
||||
|
||||
/* Define some external variables for error handling */
|
||||
|
||||
/*
|
||||
@@ -49,11 +48,11 @@
|
||||
*/
|
||||
static struct my_err_head
|
||||
{
|
||||
struct my_err_head *meh_next; /* chain link */
|
||||
const char **meh_errmsgs; /* error messages array */
|
||||
int meh_first; /* error number matching array slot 0 */
|
||||
int meh_last; /* error number matching last slot */
|
||||
} my_errmsgs_globerrs = {NULL, globerrs, EE_ERROR_FIRST, EE_ERROR_LAST};
|
||||
struct my_err_head *meh_next; /* chain link */
|
||||
const char** (*get_errmsgs) (); /* returns error message format */
|
||||
int meh_first; /* error number matching array slot 0 */
|
||||
int meh_last; /* error number matching last slot */
|
||||
} my_errmsgs_globerrs = {NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST};
|
||||
|
||||
static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
|
||||
|
||||
@@ -67,12 +66,9 @@ static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
|
||||
MyFlags Flags
|
||||
... variable list
|
||||
|
||||
RETURN
|
||||
What (*error_handler_hook)() returns:
|
||||
0 OK
|
||||
*/
|
||||
|
||||
int my_error(int nr, myf MyFlags, ...)
|
||||
void my_error(int nr, myf MyFlags, ...)
|
||||
{
|
||||
const char *format;
|
||||
struct my_err_head *meh_p;
|
||||
@@ -88,15 +84,17 @@ int my_error(int nr, myf MyFlags, ...)
|
||||
|
||||
/* get the error message string. Default, if NULL or empty string (""). */
|
||||
if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
|
||||
meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format)
|
||||
meh_p->get_errmsgs()[nr - meh_p->meh_first] : NULL) || ! *format)
|
||||
(void) my_snprintf (ebuff, sizeof(ebuff), "Unknown error %d", nr);
|
||||
else
|
||||
{
|
||||
va_start(args,MyFlags);
|
||||
(void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
|
||||
(void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
|
||||
sizeof(ebuff), format, args);
|
||||
va_end(args);
|
||||
}
|
||||
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
|
||||
(*error_handler_hook)(nr, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +109,7 @@ int my_error(int nr, myf MyFlags, ...)
|
||||
... variable list
|
||||
*/
|
||||
|
||||
int my_printf_error(uint error, const char *format, myf MyFlags, ...)
|
||||
void my_printf_error(uint error, const char *format, myf MyFlags, ...)
|
||||
{
|
||||
va_list args;
|
||||
char ebuff[ERRMSGSIZE];
|
||||
@@ -120,9 +118,34 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...)
|
||||
error, MyFlags, errno, format));
|
||||
|
||||
va_start(args,MyFlags);
|
||||
(void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
|
||||
(void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff,
|
||||
sizeof(ebuff), format, args);
|
||||
va_end(args);
|
||||
DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
|
||||
(*error_handler_hook)(error, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Error with va_list
|
||||
|
||||
SYNOPSIS
|
||||
my_printv_error()
|
||||
error Errno
|
||||
format Format string
|
||||
MyFlags Flags
|
||||
... variable list
|
||||
*/
|
||||
|
||||
void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
|
||||
{
|
||||
char ebuff[ERRMSGSIZE];
|
||||
DBUG_ENTER("my_printv_error");
|
||||
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
|
||||
error, MyFlags, errno, format));
|
||||
|
||||
(void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
|
||||
(*error_handler_hook)(error, ebuff, MyFlags);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,9 +158,9 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...)
|
||||
MyFlags Flags
|
||||
*/
|
||||
|
||||
int my_message(uint error, const char *str, register myf MyFlags)
|
||||
void my_message(uint error, const char *str, register myf MyFlags)
|
||||
{
|
||||
return (*error_handler_hook)(error, str, MyFlags);
|
||||
(*error_handler_hook)(error, str, MyFlags);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +186,7 @@ int my_message(uint error, const char *str, register myf MyFlags)
|
||||
!= 0 Error
|
||||
*/
|
||||
|
||||
int my_error_register(const char **errmsgs, int first, int last)
|
||||
int my_error_register(const char** (*get_errmsgs) (), int first, int last)
|
||||
{
|
||||
struct my_err_head *meh_p;
|
||||
struct my_err_head **search_meh_pp;
|
||||
@@ -172,7 +195,7 @@ int my_error_register(const char **errmsgs, int first, int last)
|
||||
if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head),
|
||||
MYF(MY_WME))))
|
||||
return 1;
|
||||
meh_p->meh_errmsgs= errmsgs;
|
||||
meh_p->get_errmsgs= get_errmsgs;
|
||||
meh_p->meh_first= first;
|
||||
meh_p->meh_last= last;
|
||||
|
||||
@@ -188,7 +211,7 @@ int my_error_register(const char **errmsgs, int first, int last)
|
||||
/* Error numbers must be unique. No overlapping is allowed. */
|
||||
if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last))
|
||||
{
|
||||
my_free((uchar*)meh_p, MYF(0));
|
||||
my_free(meh_p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -243,8 +266,8 @@ const char **my_error_unregister(int first, int last)
|
||||
*search_meh_pp= meh_p->meh_next;
|
||||
|
||||
/* Save the return value and free the header. */
|
||||
errmsgs= meh_p->meh_errmsgs;
|
||||
my_free((uchar*) meh_p, MYF(0));
|
||||
errmsgs= meh_p->get_errmsgs();
|
||||
my_free(meh_p);
|
||||
|
||||
return errmsgs;
|
||||
}
|
||||
@@ -259,7 +282,7 @@ void my_error_unregister_all(void)
|
||||
/* We need this ptr, but we're about to free its container, so save it. */
|
||||
saved_next= cursor->meh_next;
|
||||
|
||||
my_free((uchar*) cursor, MYF(0));
|
||||
my_free(cursor);
|
||||
}
|
||||
my_errmsgs_globerrs.meh_next= NULL; /* Freed in first iteration above. */
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ uint my_set_max_open_files(uint files)
|
||||
DBUG_ENTER("my_set_max_open_files");
|
||||
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit));
|
||||
|
||||
files+= MY_FILE_MIN;
|
||||
files= set_max_open_files(min(files, OS_FILE_LIMIT));
|
||||
if (files <= MY_NFILE)
|
||||
DBUG_RETURN(files);
|
||||
@@ -126,7 +127,7 @@ void my_free_open_file_info()
|
||||
/* Copy data back for my_print_open_files */
|
||||
memcpy((char*) my_file_info_default, my_file_info,
|
||||
sizeof(*my_file_info_default)* MY_NFILE);
|
||||
my_free((char*) my_file_info, MYF(0));
|
||||
my_free(my_file_info);
|
||||
my_file_info= my_file_info_default;
|
||||
my_file_limit= MY_NFILE;
|
||||
}
|
||||
|
||||
+168
-33
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,6 +18,10 @@
|
||||
#include <errno.h>
|
||||
#include "mysys_err.h"
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
extern int getosreldate(void);
|
||||
#endif
|
||||
|
||||
static void make_ftype(char * to,int flag);
|
||||
|
||||
/*
|
||||
@@ -41,24 +45,14 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
DBUG_ENTER("my_fopen");
|
||||
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
|
||||
filename, flags, MyFlags));
|
||||
/*
|
||||
if we are not creating, then we need to use my_access to make sure
|
||||
the file exists since Windows doesn't handle files like "com1.sym"
|
||||
very well
|
||||
*/
|
||||
#ifdef __WIN__
|
||||
if (check_if_legal_filename(filename))
|
||||
{
|
||||
errno= EACCES;
|
||||
fd= 0;
|
||||
}
|
||||
else
|
||||
|
||||
make_ftype(type,flags);
|
||||
|
||||
#ifdef _WIN32
|
||||
fd= my_win_fopen(filename, type);
|
||||
#else
|
||||
fd= fopen(filename, type);
|
||||
#endif
|
||||
{
|
||||
make_ftype(type,flags);
|
||||
fd = fopen(filename, type);
|
||||
}
|
||||
|
||||
if (fd != 0)
|
||||
{
|
||||
/*
|
||||
@@ -66,23 +60,25 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
on some OS (SUNOS). Actually the filename save isn't that important
|
||||
so we can ignore if this doesn't work.
|
||||
*/
|
||||
if ((uint) fileno(fd) >= my_file_limit)
|
||||
|
||||
int filedesc= my_fileno(fd);
|
||||
if ((uint)filedesc >= my_file_limit)
|
||||
{
|
||||
thread_safe_increment(my_stream_opened,&THR_LOCK_open);
|
||||
DBUG_RETURN(fd); /* safeguard */
|
||||
}
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[fileno(fd)].name = (char*)
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[filedesc].name= (char*)
|
||||
my_strdup(filename,MyFlags)))
|
||||
{
|
||||
my_stream_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
my_file_info[filedesc].type= STREAM_BY_FOPEN;
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
|
||||
DBUG_RETURN(fd);
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
(void) my_fclose(fd,MyFlags);
|
||||
my_errno=ENOMEM;
|
||||
}
|
||||
@@ -97,17 +93,151 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
|
||||
} /* my_fopen */
|
||||
|
||||
|
||||
/* Close a stream */
|
||||
#if defined(_WIN32)
|
||||
|
||||
static FILE *my_win_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
int handle_fd, fd= _fileno(stream);
|
||||
HANDLE osfh;
|
||||
|
||||
DBUG_ASSERT(path && stream);
|
||||
|
||||
/* Services don't have stdout/stderr on Windows, so _fileno returns -1. */
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!freopen(path, mode, stream))
|
||||
return NULL;
|
||||
|
||||
fd= _fileno(stream);
|
||||
}
|
||||
|
||||
if ((osfh= CreateFile(path, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
||||
NULL)) == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
if ((handle_fd= _open_osfhandle((intptr_t)osfh,
|
||||
_O_APPEND | _O_TEXT)) == -1)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_dup2(handle_fd, fd) < 0)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_close(handle_fd);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
/* No close operation hook. */
|
||||
|
||||
static int no_close(void *cookie __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
A hack around a race condition in the implementation of freopen.
|
||||
|
||||
The race condition steams from the fact that the current fd of
|
||||
the stream is closed before its number is used to duplicate the
|
||||
new file descriptor. This defeats the desired atomicity of the
|
||||
close and duplicate of dup2().
|
||||
|
||||
See PR number 79887 for reference:
|
||||
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
|
||||
*/
|
||||
|
||||
static FILE *my_freebsd_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
int old_fd;
|
||||
FILE *result;
|
||||
|
||||
flockfile(stream);
|
||||
|
||||
old_fd= fileno(stream);
|
||||
|
||||
/* Use a no operation close hook to avoid having the fd closed. */
|
||||
stream->_close= no_close;
|
||||
|
||||
/* Relies on the implicit dup2 to close old_fd. */
|
||||
result= freopen(path, mode, stream);
|
||||
|
||||
/* If successful, the _close hook was replaced. */
|
||||
|
||||
if (result == NULL)
|
||||
close(old_fd);
|
||||
else
|
||||
funlockfile(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Change the file associated with a file stream.
|
||||
|
||||
@param path Path to file.
|
||||
@param mode Mode of the stream.
|
||||
@param stream File stream.
|
||||
|
||||
@note
|
||||
This function is used to redirect stdout and stderr to a file and
|
||||
subsequently to close and reopen that file for log rotation.
|
||||
|
||||
@retval A FILE pointer on success. Otherwise, NULL.
|
||||
*/
|
||||
|
||||
FILE *my_freopen(const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
FILE *result;
|
||||
|
||||
#if defined(_WIN32)
|
||||
result= my_win_freopen(path, mode, stream);
|
||||
#elif defined(__FreeBSD__)
|
||||
/*
|
||||
XXX: Once the fix is ported to the stable releases, this should
|
||||
be dependent upon the specific FreeBSD versions. Check at:
|
||||
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
|
||||
*/
|
||||
if (getosreldate() > 900027)
|
||||
result= freopen(path, mode, stream);
|
||||
else
|
||||
result= my_freebsd_freopen(path, mode, stream);
|
||||
#else
|
||||
result= freopen(path, mode, stream);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Close a stream */
|
||||
int my_fclose(FILE *fd, myf MyFlags)
|
||||
{
|
||||
int err,file;
|
||||
DBUG_ENTER("my_fclose");
|
||||
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
file=fileno(fd);
|
||||
if ((err = fclose(fd)) < 0)
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
file= my_fileno(fd);
|
||||
#ifndef _WIN32
|
||||
err= fclose(fd);
|
||||
#else
|
||||
err= my_win_fclose(fd);
|
||||
#endif
|
||||
if(err < 0)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
@@ -119,9 +249,9 @@ int my_fclose(FILE *fd, myf MyFlags)
|
||||
if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN)
|
||||
{
|
||||
my_file_info[file].type = UNOPEN;
|
||||
my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(my_file_info[file].name);
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_RETURN(err);
|
||||
} /* my_fclose */
|
||||
|
||||
@@ -138,7 +268,12 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
|
||||
Filedes, Flags, MyFlags));
|
||||
|
||||
make_ftype(type,Flags);
|
||||
if ((fd = fdopen(Filedes, type)) == 0)
|
||||
#ifdef _WIN32
|
||||
fd= my_win_fdopen(Filedes, type);
|
||||
#else
|
||||
fd= fdopen(Filedes, type);
|
||||
#endif
|
||||
if (!fd)
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE | MY_WME))
|
||||
@@ -146,7 +281,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
my_stream_opened++;
|
||||
if ((uint) Filedes < (uint) my_file_limit)
|
||||
{
|
||||
@@ -160,7 +295,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
|
||||
}
|
||||
my_file_info[Filedes].type = STREAM_BY_FDOPEN;
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
}
|
||||
|
||||
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
|
||||
|
||||
@@ -56,11 +56,11 @@ size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
if (ferror(stream))
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
else
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
my_errno=errno ? errno : -1;
|
||||
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
|
||||
@@ -119,21 +119,20 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
#ifdef EINTR
|
||||
if (errno == EINTR)
|
||||
{
|
||||
VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
|
||||
(void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
|
||||
#ifdef THREAD
|
||||
if (my_thread_var->abort)
|
||||
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
|
||||
#endif
|
||||
|
||||
if ((errno == ENOSPC || errno == EDQUOT) &&
|
||||
(MyFlags & MY_WAIT_IF_FULL))
|
||||
{
|
||||
wait_for_free_space("[stream]", errors);
|
||||
errors++;
|
||||
VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
|
||||
(void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@@ -142,7 +141,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(fileno(stream)),errno);
|
||||
my_filename(my_fileno(stream)),errno);
|
||||
}
|
||||
writtenbytes= (size_t) -1; /* Return that we got error */
|
||||
break;
|
||||
@@ -182,3 +181,14 @@ my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
|
||||
DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
|
||||
DBUG_RETURN((my_off_t) pos);
|
||||
} /* my_ftell */
|
||||
|
||||
|
||||
/* Get a File corresponding to the stream*/
|
||||
int my_fileno(FILE *f)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return my_win_fileno(f);
|
||||
#else
|
||||
return fileno(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2002, 2004 MySQL AB
|
||||
/* Copyright (C) 2002, 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
@@ -78,9 +78,7 @@ struct hostent *my_gethostbyname_r(const char *name,
|
||||
|
||||
#else /* !HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
#ifdef THREAD
|
||||
extern pthread_mutex_t LOCK_gethostbyname_r;
|
||||
#endif
|
||||
extern mysql_mutex_t LOCK_gethostbyname_r;
|
||||
|
||||
/*
|
||||
No gethostbyname_r() function exists.
|
||||
@@ -92,11 +90,13 @@ extern pthread_mutex_t LOCK_gethostbyname_r;
|
||||
*/
|
||||
|
||||
struct hostent *my_gethostbyname_r(const char *name,
|
||||
struct hostent *result, char *buffer,
|
||||
int buflen, int *h_errnop)
|
||||
struct hostent *res __attribute__((unused)),
|
||||
char *buffer __attribute__((unused)),
|
||||
int buflen __attribute__((unused)),
|
||||
int *h_errnop)
|
||||
{
|
||||
struct hostent *hp;
|
||||
pthread_mutex_lock(&LOCK_gethostbyname_r);
|
||||
mysql_mutex_lock(&LOCK_gethostbyname_r);
|
||||
hp= gethostbyname(name);
|
||||
*h_errnop= h_errno;
|
||||
return hp;
|
||||
@@ -104,7 +104,7 @@ struct hostent *my_gethostbyname_r(const char *name,
|
||||
|
||||
void my_gethostbyname_r_free()
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_gethostbyname_r);
|
||||
mysql_mutex_unlock(&LOCK_gethostbyname_r);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* get hardware address for an interface */
|
||||
/* if there are many available, any non-zero one can be used */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#ifndef MAIN
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
size_t len;
|
||||
char *buf, *next, *end;
|
||||
struct if_msghdr *ifm;
|
||||
struct sockaddr_dl *sdl;
|
||||
int res=1, mib[6]={CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0};
|
||||
char zero_array[ETHER_ADDR_LEN] = {0};
|
||||
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
|
||||
goto err;
|
||||
if (!(buf = alloca(len)))
|
||||
goto err;
|
||||
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
|
||||
goto err;
|
||||
|
||||
end = buf + len;
|
||||
|
||||
for (next = buf ; res && next < end ; next += ifm->ifm_msglen)
|
||||
{
|
||||
ifm = (struct if_msghdr *)next;
|
||||
if (ifm->ifm_type == RTM_IFINFO)
|
||||
{
|
||||
sdl= (struct sockaddr_dl *)(ifm + 1);
|
||||
memcpy(to, LLADDR(sdl), ETHER_ADDR_LEN);
|
||||
res= memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif __linux__
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
int fd, res= 1;
|
||||
struct ifreq ifr;
|
||||
char zero_array[ETHER_ADDR_LEN] = {0};
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
goto err;
|
||||
|
||||
bzero(&ifr, sizeof(ifr));
|
||||
strnmov(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name) - 1);
|
||||
|
||||
do
|
||||
{
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0)
|
||||
{
|
||||
memcpy(to, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
|
||||
res= memcmp(to, zero_array, ETHER_ADDR_LEN) ? 0 : 1;
|
||||
}
|
||||
} while (res && (errno == 0 || errno == ENODEV) && ifr.ifr_name[3]++ < '6');
|
||||
|
||||
close(fd);
|
||||
err:
|
||||
return res;
|
||||
}
|
||||
|
||||
#elif defined(__WIN__)
|
||||
|
||||
/*
|
||||
Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with
|
||||
windows headers)
|
||||
*/
|
||||
#ifdef VOID
|
||||
#undef VOID
|
||||
#define VOID void
|
||||
#endif
|
||||
|
||||
#include <iphlpapi.h>
|
||||
|
||||
/*
|
||||
The following typedef is for dynamically loading iphlpapi.dll /
|
||||
GetAdaptersAddresses. Dynamic loading is used because
|
||||
GetAdaptersAddresses is not available on Windows 2000 which MySQL
|
||||
still supports. Static linking would cause an unresolved export.
|
||||
*/
|
||||
typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family,
|
||||
IN DWORD Flags,IN PVOID Reserved,
|
||||
OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses,
|
||||
IN OUT PULONG pOutBufLen);
|
||||
|
||||
/*
|
||||
my_gethwaddr - Windows version
|
||||
|
||||
@brief Retrieve MAC address from network hardware
|
||||
|
||||
@param[out] to MAC address exactly six bytes
|
||||
|
||||
@return Operation status
|
||||
@retval 0 OK
|
||||
@retval <>0 FAILED
|
||||
*/
|
||||
my_bool my_gethwaddr(uchar *to)
|
||||
{
|
||||
PIP_ADAPTER_ADDRESSES pAdapterAddresses;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses;
|
||||
IP_ADAPTER_ADDRESSES adapterAddresses;
|
||||
ULONG address_len;
|
||||
my_bool return_val= 1;
|
||||
static pfnGetAdaptersAddresses fnGetAdaptersAddresses=
|
||||
(pfnGetAdaptersAddresses)-1;
|
||||
|
||||
if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1)
|
||||
{
|
||||
/* Get the function from the DLL */
|
||||
fnGetAdaptersAddresses= (pfnGetAdaptersAddresses)
|
||||
GetProcAddress(LoadLibrary("iphlpapi.dll"),
|
||||
"GetAdaptersAddresses");
|
||||
}
|
||||
if (!fnGetAdaptersAddresses)
|
||||
return 1; /* failed to get function */
|
||||
address_len= sizeof (IP_ADAPTER_ADDRESSES);
|
||||
|
||||
/* Get the required size for the address data. */
|
||||
if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len)
|
||||
== ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
pAdapterAddresses= my_malloc(address_len, 0);
|
||||
if (!pAdapterAddresses)
|
||||
return 1; /* error, alloc failed */
|
||||
}
|
||||
else
|
||||
pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */
|
||||
|
||||
/* Get the hardware info. */
|
||||
if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len)
|
||||
== NO_ERROR)
|
||||
{
|
||||
pCurrAddresses= pAdapterAddresses;
|
||||
|
||||
while (pCurrAddresses)
|
||||
{
|
||||
/* Look for ethernet cards. */
|
||||
if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD)
|
||||
{
|
||||
/* check for a good address */
|
||||
if (pCurrAddresses->PhysicalAddressLength < 6)
|
||||
continue; /* bad address */
|
||||
|
||||
/* save 6 bytes of the address in the 'to' parameter */
|
||||
memcpy(to, pCurrAddresses->PhysicalAddress, 6);
|
||||
|
||||
/* Network card found, we're done. */
|
||||
return_val= 0;
|
||||
break;
|
||||
}
|
||||
pCurrAddresses= pCurrAddresses->Next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up memory allocation. */
|
||||
if (pAdapterAddresses != &adapterAddresses)
|
||||
my_free(pAdapterAddresses);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
#else /* __FreeBSD__ || __linux__ || __WIN__ */
|
||||
/* just fail */
|
||||
my_bool my_gethwaddr(uchar *to __attribute__((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* MAIN */
|
||||
int main(int argc __attribute__((unused)),char **argv)
|
||||
{
|
||||
uchar mac[6];
|
||||
uint i;
|
||||
MY_INIT(argv[0]);
|
||||
if (my_gethwaddr(mac))
|
||||
{
|
||||
printf("my_gethwaddr failed with errno %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
for (i=0; i < sizeof(mac); i++)
|
||||
{
|
||||
if (i) printf(":");
|
||||
printf("%02x", mac[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Copyright (C) 2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* get the number of (online) CPUs */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static int ncpus=0;
|
||||
|
||||
int my_getncpus()
|
||||
{
|
||||
if (!ncpus)
|
||||
{
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
ncpus= sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#elif defined(__WIN__)
|
||||
SYSTEM_INFO sysinfo;
|
||||
|
||||
/*
|
||||
* We are not calling GetNativeSystemInfo here because (1) we
|
||||
* don't believe that they return different values for number
|
||||
* of processors and (2) if WOW64 limits processors for Win32
|
||||
* then we don't want to try to override that.
|
||||
*/
|
||||
GetSystemInfo(&sysinfo);
|
||||
|
||||
ncpus= sysinfo.dwNumberOfProcessors;
|
||||
#else
|
||||
/* unknown so play safe: assume SMP and forbid uniprocessor build */
|
||||
ncpus= 2;
|
||||
#endif
|
||||
}
|
||||
return ncpus;
|
||||
}
|
||||
+376
-244
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2002-2006 MySQL AB
|
||||
/* Copyright (C) 2002-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -28,24 +28,15 @@ typedef void (*init_func_p)(const struct my_option *option, void *variable,
|
||||
static void default_reporter(enum loglevel level, const char *format, ...);
|
||||
my_error_reporter my_getopt_error_reporter= &default_reporter;
|
||||
|
||||
static int findopt(char *optpat, uint length,
|
||||
const struct my_option **opt_res,
|
||||
const char **ffname);
|
||||
my_bool getopt_compare_strings(const char *s,
|
||||
const char *t,
|
||||
uint length);
|
||||
static int findopt(char *, uint, const struct my_option **, const char **);
|
||||
my_bool getopt_compare_strings(const char *, const char *, uint);
|
||||
static longlong getopt_ll(char *arg, const struct my_option *optp, int *err);
|
||||
static ulonglong getopt_ull(char *arg, const struct my_option *optp,
|
||||
int *err);
|
||||
static ulonglong getopt_ull(char *, const struct my_option *, int *);
|
||||
static double getopt_double(char *arg, const struct my_option *optp, int *err);
|
||||
static void init_variables(const struct my_option *options,
|
||||
init_func_p init_one_value);
|
||||
static void init_one_value(const struct my_option *option, void *variable,
|
||||
longlong value);
|
||||
static void fini_one_value(const struct my_option *option, void *variable,
|
||||
longlong value);
|
||||
static int setval(const struct my_option *opts, void *value, char *argument,
|
||||
my_bool set_maximum_value);
|
||||
static void init_variables(const struct my_option *, init_func_p);
|
||||
static void init_one_value(const struct my_option *, void *, longlong);
|
||||
static void fini_one_value(const struct my_option *, void *, longlong);
|
||||
static int setval(const struct my_option *, void *, char *, my_bool);
|
||||
static char *check_struct_option(char *cur_arg, char *key_name);
|
||||
|
||||
/*
|
||||
@@ -60,6 +51,7 @@ enum enum_special_opt
|
||||
{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE};
|
||||
|
||||
char *disabled_my_option= (char*) "0";
|
||||
char *enabled_my_option= (char*) "1";
|
||||
|
||||
/*
|
||||
This is a flag that can be set in client programs. 0 means that
|
||||
@@ -91,16 +83,6 @@ static void default_reporter(enum loglevel level,
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/*
|
||||
function: handle_options
|
||||
|
||||
Sort options; put options first, until special end of options (--), or
|
||||
until end of argv. Parse options; check that the given option matches with
|
||||
one of the options in struct 'my_option', return error in case of ambiguous
|
||||
or unknown option. Check that option was given an argument if it requires
|
||||
one. Call function 'get_one_option()' once for each option.
|
||||
*/
|
||||
|
||||
static my_getopt_value getopt_get_addr;
|
||||
|
||||
void my_getopt_register_get_addr(my_getopt_value func_addr)
|
||||
@@ -108,11 +90,70 @@ void my_getopt_register_get_addr(my_getopt_value func_addr)
|
||||
getopt_get_addr= func_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
Handle command line options.
|
||||
Sort options.
|
||||
Put options first, until special end of options (--),
|
||||
or until the end of argv. Parse options, check that the given option
|
||||
matches with one of the options in struct 'my_option'.
|
||||
Check that option was given an argument if it requires one
|
||||
Call the optional 'get_one_option()' function once for each option.
|
||||
|
||||
Note that handle_options() can be invoked multiple times to
|
||||
parse a command line in several steps.
|
||||
In this case, use the global flag @c my_getopt_skip_unknown to indicate
|
||||
that options unknown in the current step should be preserved in the
|
||||
command line for later parsing in subsequent steps.
|
||||
|
||||
For 'long' options (--a_long_option), @c my_getopt_skip_unknown is
|
||||
fully supported. Command line parameters such as:
|
||||
- "--a_long_option"
|
||||
- "--a_long_option=value"
|
||||
- "--a_long_option value"
|
||||
will be preserved as is when the option is not known.
|
||||
|
||||
For 'short' options (-S), support for @c my_getopt_skip_unknown
|
||||
comes with some limitation, because several short options
|
||||
can also be specified together in the same command line argument,
|
||||
as in "-XYZ".
|
||||
|
||||
The first use case supported is: all short options are declared.
|
||||
handle_options() will be able to interpret "-XYZ" as one of:
|
||||
- an unknown X option
|
||||
- "-X -Y -Z", three short options with no arguments
|
||||
- "-X -YZ", where Y is a short option with argument Z
|
||||
- "-XYZ", where X is a short option with argument YZ
|
||||
based on the full short options specifications.
|
||||
|
||||
The second use case supported is: no short option is declared.
|
||||
handle_options() will reject "-XYZ" as unknown, to be parsed later.
|
||||
|
||||
The use case that is explicitly not supported is to provide
|
||||
only a partial list of short options to handle_options().
|
||||
This function can not be expected to extract some option Y
|
||||
in the middle of the string "-XYZ" in these conditions,
|
||||
without knowing if X will be declared an option later.
|
||||
|
||||
Note that this limitation only impacts parsing of several
|
||||
short options from the same command line argument,
|
||||
as in "mysqld -anW5".
|
||||
When each short option is properly separated out in the command line
|
||||
argument, for example in "mysqld -a -n -w5", the code would actually
|
||||
work even with partial options specs given at each stage.
|
||||
|
||||
@param [in, out] argc command line options (count)
|
||||
@param [in, out] argv command line options (values)
|
||||
@param [in] longopts descriptor of all valid options
|
||||
@param [in] get_one_option optional callback function to process each option,
|
||||
can be NULL.
|
||||
@return error in case of ambiguous or unknown options,
|
||||
0 on success.
|
||||
*/
|
||||
int handle_options(int *argc, char ***argv,
|
||||
const struct my_option *longopts,
|
||||
my_get_one_option get_one_option)
|
||||
{
|
||||
uint opt_found, argvpos= 0, length;
|
||||
uint UNINIT_VAR(opt_found), argvpos= 0, length;
|
||||
my_bool end_of_options= 0, must_be_var, set_maximum_value,
|
||||
option_is_loose;
|
||||
char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN];
|
||||
@@ -120,8 +161,8 @@ int handle_options(int *argc, char ***argv,
|
||||
const struct my_option *optp;
|
||||
void *value;
|
||||
int error, i;
|
||||
my_bool is_cmdline_arg= 1;
|
||||
|
||||
LINT_INIT(opt_found);
|
||||
/* handle_options() assumes arg0 (program name) always exists */
|
||||
DBUG_ASSERT(argc && *argc >= 1);
|
||||
DBUG_ASSERT(argv && *argv);
|
||||
@@ -129,10 +170,35 @@ int handle_options(int *argc, char ***argv,
|
||||
(*argv)++; /* --- || ---- */
|
||||
init_variables(longopts, init_one_value);
|
||||
|
||||
/*
|
||||
Search for args_separator, if found, then the first part of the
|
||||
arguments are loaded from configs
|
||||
*/
|
||||
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
|
||||
{
|
||||
if (*pos == args_separator)
|
||||
{
|
||||
is_cmdline_arg= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
|
||||
{
|
||||
char **first= pos;
|
||||
char *cur_arg= *pos;
|
||||
opt_found= 0;
|
||||
if (!is_cmdline_arg && (cur_arg == args_separator))
|
||||
{
|
||||
is_cmdline_arg= 1;
|
||||
|
||||
/* save the separator too if skip unkown options */
|
||||
if (my_getopt_skip_unknown)
|
||||
(*argv)[argvpos++]= cur_arg;
|
||||
else
|
||||
(*argc)--;
|
||||
continue;
|
||||
}
|
||||
if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
|
||||
{
|
||||
char *argument= 0;
|
||||
@@ -141,78 +207,15 @@ int handle_options(int *argc, char ***argv,
|
||||
option_is_loose= 0;
|
||||
|
||||
cur_arg++; /* skip '-' */
|
||||
if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */
|
||||
{ /* --set-variable, or -O */
|
||||
if (*cur_arg == 'O')
|
||||
{
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"%s: Option '-O' is deprecated. "
|
||||
"Use --variable-name=value instead.",
|
||||
my_progname);
|
||||
must_be_var= 1;
|
||||
|
||||
if (!(*++cur_arg)) /* If not -Ovar=# */
|
||||
{
|
||||
/* the argument must be in next argv */
|
||||
if (!*++pos)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Option '-O' requires an argument",
|
||||
my_progname);
|
||||
return EXIT_ARGUMENT_REQUIRED;
|
||||
}
|
||||
cur_arg= *pos;
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
else if (!getopt_compare_strings(cur_arg, "-set-variable", 13))
|
||||
{
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"%s: Option '--set-variable' is deprecated. "
|
||||
"Use --variable-name=value instead.",
|
||||
my_progname);
|
||||
|
||||
must_be_var= 1;
|
||||
if (cur_arg[13] == '=')
|
||||
{
|
||||
cur_arg+= 14;
|
||||
if (!*cur_arg)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Option '--set-variable' requires an argument",
|
||||
my_progname);
|
||||
return EXIT_ARGUMENT_REQUIRED;
|
||||
}
|
||||
}
|
||||
else if (cur_arg[14]) /* garbage, or another option. break out */
|
||||
must_be_var= 0;
|
||||
else
|
||||
{
|
||||
/* the argument must be in next argv */
|
||||
if (!*++pos)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Option '--set-variable' requires an argument",
|
||||
my_progname);
|
||||
return EXIT_ARGUMENT_REQUIRED;
|
||||
}
|
||||
cur_arg= *pos;
|
||||
(*argc)--;
|
||||
}
|
||||
}
|
||||
else if (!must_be_var)
|
||||
{
|
||||
if (!*++cur_arg) /* skip the double dash */
|
||||
{
|
||||
/* '--' means end of options, look no further */
|
||||
end_of_options= 1;
|
||||
(*argc)--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (*cur_arg == '-') /* check for long option, */
|
||||
{
|
||||
if (!*++cur_arg) /* skip the double dash */
|
||||
{
|
||||
/* '--' means end of options, look no further */
|
||||
end_of_options= 1;
|
||||
(*argc)--;
|
||||
continue;
|
||||
}
|
||||
opt_str= check_struct_option(cur_arg, key_name);
|
||||
optend= strcend(opt_str, '=');
|
||||
length= (uint) (optend - opt_str);
|
||||
@@ -258,7 +261,7 @@ int handle_options(int *argc, char ***argv,
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: ambiguous option '--%s-%s' (--%s-%s)",
|
||||
my_progname, special_opt_prefix[i],
|
||||
cur_arg, special_opt_prefix[i],
|
||||
opt_str, special_opt_prefix[i],
|
||||
prev_found);
|
||||
return EXIT_AMBIGUOUS_OPTION;
|
||||
}
|
||||
@@ -270,11 +273,11 @@ int handle_options(int *argc, char ***argv,
|
||||
for example: --skip-option=0 -> option = TRUE
|
||||
*/
|
||||
optend= (optend && *optend == '0' && !(*(optend + 1))) ?
|
||||
(char*) "1" : disabled_my_option;
|
||||
enabled_my_option : disabled_my_option;
|
||||
break;
|
||||
case OPT_ENABLE:
|
||||
optend= (optend && *optend == '0' && !(*(optend + 1))) ?
|
||||
disabled_my_option : (char*) "1";
|
||||
disabled_my_option : enabled_my_option;
|
||||
break;
|
||||
case OPT_MAXIMUM:
|
||||
set_maximum_value= 1;
|
||||
@@ -291,12 +294,7 @@ int handle_options(int *argc, char ***argv,
|
||||
{
|
||||
if (my_getopt_skip_unknown)
|
||||
{
|
||||
/*
|
||||
preserve all the components of this unknown option, this may
|
||||
occurr when the user provides options like: "-O foo" or
|
||||
"--set-variable foo" (note that theres a space in there)
|
||||
Generally, these kind of options are to be avoided
|
||||
*/
|
||||
/* Preserve all the components of this unknown option. */
|
||||
do {
|
||||
(*argv)[argvpos++]= *first++;
|
||||
} while (first <= pos);
|
||||
@@ -362,14 +360,6 @@ int handle_options(int *argc, char ***argv,
|
||||
}
|
||||
return EXIT_OPTION_DISABLED;
|
||||
}
|
||||
if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: option '%s' cannot take an argument",
|
||||
my_progname, optp->name);
|
||||
return EXIT_NO_ARGUMENT_ALLOWED;
|
||||
}
|
||||
error= 0;
|
||||
value= optp->var_type & GET_ASK_ADDR ?
|
||||
(*getopt_get_addr)(key_name, (uint) strlen(key_name), optp, &error) :
|
||||
@@ -379,6 +369,11 @@ int handle_options(int *argc, char ***argv,
|
||||
|
||||
if (optp->arg_type == NO_ARG)
|
||||
{
|
||||
/*
|
||||
Due to historical reasons GET_BOOL var_types still accepts arguments
|
||||
despite the NO_ARG arg_type attribute. This can seems a bit unintuitive
|
||||
and care should be taken when refactoring this code.
|
||||
*/
|
||||
if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
@@ -393,7 +388,7 @@ int handle_options(int *argc, char ***argv,
|
||||
Set bool to 1 if no argument or if the user has used
|
||||
--enable-'option-name'.
|
||||
*optend was set to '0' if one used --disable-option
|
||||
*/
|
||||
*/
|
||||
(*argc)--;
|
||||
if (!optend || *optend == '1' ||
|
||||
!my_strcasecmp(&my_charset_latin1, optend, "true"))
|
||||
@@ -404,37 +399,26 @@ int handle_options(int *argc, char ***argv,
|
||||
else
|
||||
{
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"%s: ignoring option '--%s' due to "
|
||||
"invalid value '%s'",
|
||||
"%s: ignoring option '--%s' "
|
||||
"due to invalid value '%s'",
|
||||
my_progname, optp->name, optend);
|
||||
continue;
|
||||
}
|
||||
if (get_one_option(optp->id, optp,
|
||||
if (get_one_option && get_one_option(optp->id, optp,
|
||||
*((my_bool*) value) ?
|
||||
(char*) "1" : disabled_my_option))
|
||||
enabled_my_option : disabled_my_option))
|
||||
return EXIT_ARGUMENT_INVALID;
|
||||
continue;
|
||||
}
|
||||
argument= optend;
|
||||
}
|
||||
else if (optp->arg_type == OPT_ARG &&
|
||||
(((optp->var_type & GET_TYPE_MASK) == GET_BOOL) ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_ENUM))
|
||||
{
|
||||
if (optend == disabled_my_option)
|
||||
init_one_value(optp, value, 0);
|
||||
else
|
||||
{
|
||||
if (!optend) /* No argument -> enable option */
|
||||
init_one_value(optp, value, 1);
|
||||
else
|
||||
argument= optend;
|
||||
}
|
||||
}
|
||||
else if (optp->arg_type == REQUIRED_ARG && !optend)
|
||||
{
|
||||
/* Check if there are more arguments after this one */
|
||||
if (!*++pos)
|
||||
/* Check if there are more arguments after this one,
|
||||
Note: options loaded from config file that requires value
|
||||
should always be in the form '--option=value'.
|
||||
*/
|
||||
if (!is_cmdline_arg || !*++pos)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
@@ -453,9 +437,9 @@ int handle_options(int *argc, char ***argv,
|
||||
for (optend= cur_arg; *optend; optend++)
|
||||
{
|
||||
opt_found= 0;
|
||||
for (optp= longopts; optp->id; optp++)
|
||||
for (optp= longopts; optp->name; optp++)
|
||||
{
|
||||
if (optp->id == (int) (uchar) *optend)
|
||||
if (optp->id && optp->id == (int) (uchar) *optend)
|
||||
{
|
||||
/* Option recognized. Find next what to do with it */
|
||||
opt_found= 1;
|
||||
@@ -471,7 +455,7 @@ int handle_options(int *argc, char ***argv,
|
||||
optp->arg_type == NO_ARG)
|
||||
{
|
||||
*((my_bool*) optp->value)= (my_bool) 1;
|
||||
if (get_one_option(optp->id, optp, argument))
|
||||
if (get_one_option && get_one_option(optp->id, optp, argument))
|
||||
return EXIT_UNSPECIFIED_ERROR;
|
||||
continue;
|
||||
}
|
||||
@@ -491,7 +475,7 @@ int handle_options(int *argc, char ***argv,
|
||||
{
|
||||
if (optp->var_type == GET_BOOL)
|
||||
*((my_bool*) optp->value)= (my_bool) 1;
|
||||
if (get_one_option(optp->id, optp, argument))
|
||||
if (get_one_option && get_one_option(optp->id, optp, argument))
|
||||
return EXIT_UNSPECIFIED_ERROR;
|
||||
continue;
|
||||
}
|
||||
@@ -511,40 +495,56 @@ int handle_options(int *argc, char ***argv,
|
||||
}
|
||||
if ((error= setval(optp, optp->value, argument,
|
||||
set_maximum_value)))
|
||||
{
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Error while setting value '%s' to '%s'",
|
||||
my_progname, argument, optp->name);
|
||||
return error;
|
||||
}
|
||||
if (get_one_option(optp->id, optp, argument))
|
||||
if (get_one_option && get_one_option(optp->id, optp, argument))
|
||||
return EXIT_UNSPECIFIED_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!opt_found)
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: unknown option '-%c'",
|
||||
my_progname, *optend);
|
||||
return EXIT_UNKNOWN_OPTION;
|
||||
if (my_getopt_skip_unknown)
|
||||
{
|
||||
/*
|
||||
We are currently parsing a single argv[] argument
|
||||
of the form "-XYZ".
|
||||
One or the argument found (say Y) is not an option.
|
||||
Hack the string "-XYZ" to make a "-YZ" substring in it,
|
||||
and push that to the output as an unrecognized parameter.
|
||||
*/
|
||||
DBUG_ASSERT(optend > *pos);
|
||||
DBUG_ASSERT(optend >= cur_arg);
|
||||
DBUG_ASSERT(optend <= *pos + strlen(*pos));
|
||||
DBUG_ASSERT(*optend);
|
||||
optend--;
|
||||
optend[0]= '-'; /* replace 'X' or '-' by '-' */
|
||||
(*argv)[argvpos++]= optend;
|
||||
/*
|
||||
Do not continue to parse at the current "-XYZ" argument,
|
||||
skip to the next argv[] argument instead.
|
||||
*/
|
||||
optend= (char*) " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (my_getopt_print_errors)
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: unknown option '-%c'",
|
||||
my_progname, *optend);
|
||||
return EXIT_UNKNOWN_OPTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
(*argc)--; /* option handled (short), decrease argument count */
|
||||
if (opt_found)
|
||||
(*argc)--; /* option handled (short), decrease argument count */
|
||||
continue;
|
||||
}
|
||||
if ((error= setval(optp, value, argument, set_maximum_value)))
|
||||
{
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Error while setting value '%s' to '%s'",
|
||||
my_progname, argument, optp->name);
|
||||
return error;
|
||||
}
|
||||
if (get_one_option(optp->id, optp, argument))
|
||||
if (get_one_option && get_one_option(optp->id, optp, argument))
|
||||
return EXIT_UNSPECIFIED_ERROR;
|
||||
|
||||
(*argc)--; /* option handled (short or long), decrease argument count */
|
||||
(*argc)--; /* option handled (long), decrease argument count */
|
||||
}
|
||||
else /* non-option found */
|
||||
(*argv)[argvpos++]= cur_arg;
|
||||
@@ -602,6 +602,24 @@ static char *check_struct_option(char *cur_arg, char *key_name)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parse a boolean command line argument
|
||||
|
||||
"ON", "TRUE" and "1" will return true,
|
||||
other values will return false.
|
||||
|
||||
@param[in] argument The value argument
|
||||
@return boolean value
|
||||
*/
|
||||
static my_bool get_bool_argument(const char *argument)
|
||||
{
|
||||
if (!my_strcasecmp(&my_charset_latin1, argument, "true") ||
|
||||
!my_strcasecmp(&my_charset_latin1, argument, "on"))
|
||||
return 1;
|
||||
else
|
||||
return (my_bool) atoi(argument);
|
||||
}
|
||||
|
||||
/*
|
||||
function: setval
|
||||
|
||||
@@ -612,75 +630,132 @@ static char *check_struct_option(char *cur_arg, char *key_name)
|
||||
static int setval(const struct my_option *opts, void *value, char *argument,
|
||||
my_bool set_maximum_value)
|
||||
{
|
||||
int err= 0;
|
||||
int err= 0, res= 0;
|
||||
|
||||
if (value && argument)
|
||||
if (!argument)
|
||||
argument= enabled_my_option;
|
||||
|
||||
if (value)
|
||||
{
|
||||
void *result_pos= ((set_maximum_value) ? opts->u_max_value : value);
|
||||
|
||||
if (!result_pos)
|
||||
if (set_maximum_value && !(value= opts->u_max_value))
|
||||
{
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Maximum value of '%s' cannot be set",
|
||||
my_progname, opts->name);
|
||||
return EXIT_NO_PTR_TO_VARIABLE;
|
||||
}
|
||||
|
||||
switch ((opts->var_type & GET_TYPE_MASK)) {
|
||||
case GET_BOOL: /* If argument differs from 0, enable option, else disable */
|
||||
*((my_bool*) result_pos)= (my_bool) atoi(argument) != 0;
|
||||
*((my_bool*) value)= get_bool_argument(argument);
|
||||
break;
|
||||
case GET_INT:
|
||||
*((int*) result_pos)= (int) getopt_ll(argument, opts, &err);
|
||||
*((int*) value)= (int) getopt_ll(argument, opts, &err);
|
||||
break;
|
||||
case GET_UINT:
|
||||
*((uint*) result_pos)= (uint) getopt_ull(argument, opts, &err);
|
||||
*((uint*) value)= (uint) getopt_ull(argument, opts, &err);
|
||||
break;
|
||||
case GET_LONG:
|
||||
*((long*) result_pos)= (long) getopt_ll(argument, opts, &err);
|
||||
*((long*) value)= (long) getopt_ll(argument, opts, &err);
|
||||
break;
|
||||
case GET_ULONG:
|
||||
*((long*) result_pos)= (long) getopt_ull(argument, opts, &err);
|
||||
*((long*) value)= (long) getopt_ull(argument, opts, &err);
|
||||
break;
|
||||
case GET_LL:
|
||||
*((longlong*) result_pos)= getopt_ll(argument, opts, &err);
|
||||
*((longlong*) value)= getopt_ll(argument, opts, &err);
|
||||
break;
|
||||
case GET_ULL:
|
||||
*((ulonglong*) result_pos)= getopt_ull(argument, opts, &err);
|
||||
*((ulonglong*) value)= getopt_ull(argument, opts, &err);
|
||||
break;
|
||||
case GET_DOUBLE:
|
||||
*((double*) result_pos)= getopt_double(argument, opts, &err);
|
||||
*((double*) value)= getopt_double(argument, opts, &err);
|
||||
break;
|
||||
case GET_STR:
|
||||
*((char**) result_pos)= argument;
|
||||
if (argument == enabled_my_option)
|
||||
break; /* string options don't use this default of "1" */
|
||||
*((char**) value)= argument;
|
||||
break;
|
||||
case GET_STR_ALLOC:
|
||||
if ((*((char**) result_pos)))
|
||||
my_free((*(char**) result_pos), MYF(MY_WME | MY_FAE));
|
||||
if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME))))
|
||||
return EXIT_OUT_OF_MEMORY;
|
||||
if (argument == enabled_my_option)
|
||||
break; /* string options don't use this default of "1" */
|
||||
my_free(*((char**) value));
|
||||
if (!(*((char**) value)= my_strdup(argument, MYF(MY_WME))))
|
||||
{
|
||||
res= EXIT_OUT_OF_MEMORY;
|
||||
goto ret;
|
||||
};
|
||||
break;
|
||||
case GET_ENUM:
|
||||
if (((*(int*)result_pos)=
|
||||
find_type(argument, opts->typelib, 2) - 1) < 0)
|
||||
{
|
||||
/*
|
||||
Accept an integer representation of the enumerated item.
|
||||
*/
|
||||
char *endptr;
|
||||
unsigned int arg= (unsigned int) strtol(argument, &endptr, 10);
|
||||
if (*endptr || arg >= opts->typelib->count)
|
||||
return EXIT_ARGUMENT_INVALID;
|
||||
*(int*)result_pos= arg;
|
||||
int type= find_type(argument, opts->typelib, 2);
|
||||
if (type == 0)
|
||||
{
|
||||
/*
|
||||
Accept an integer representation of the enumerated item.
|
||||
*/
|
||||
char *endptr;
|
||||
ulong arg= strtoul(argument, &endptr, 10);
|
||||
if (*endptr || arg >= opts->typelib->count)
|
||||
{
|
||||
res= EXIT_ARGUMENT_INVALID;
|
||||
goto ret;
|
||||
}
|
||||
*(ulong*)value= arg;
|
||||
}
|
||||
else
|
||||
*(ulong*)value= type - 1;
|
||||
}
|
||||
break;
|
||||
case GET_SET:
|
||||
*((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err);
|
||||
*((ulonglong*)value)= find_typeset(argument, opts->typelib, &err);
|
||||
if (err)
|
||||
return EXIT_ARGUMENT_INVALID;
|
||||
{
|
||||
/* Accept an integer representation of the set */
|
||||
char *endptr;
|
||||
ulonglong arg= (ulonglong) strtol(argument, &endptr, 10);
|
||||
if (*endptr || (arg >> 1) >= (1ULL << (opts->typelib->count-1)))
|
||||
{
|
||||
res= EXIT_ARGUMENT_INVALID;
|
||||
goto ret;
|
||||
};
|
||||
*(ulonglong*)value= arg;
|
||||
err= 0;
|
||||
}
|
||||
break;
|
||||
default: /* dummy default to avoid compiler warnings */
|
||||
case GET_FLAGSET:
|
||||
{
|
||||
char *error;
|
||||
uint error_len;
|
||||
|
||||
*((ulonglong*)value)=
|
||||
find_set_from_flags(opts->typelib, opts->typelib->count,
|
||||
*(ulonglong *)value, opts->def_value,
|
||||
argument, strlen(argument),
|
||||
&error, &error_len);
|
||||
if (error)
|
||||
{
|
||||
res= EXIT_ARGUMENT_INVALID;
|
||||
goto ret;
|
||||
};
|
||||
}
|
||||
break;
|
||||
case GET_NO_ARG: /* get_one_option has taken care of the value already */
|
||||
default: /* dummy default to avoid compiler warnings */
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
return EXIT_UNKNOWN_SUFFIX;
|
||||
{
|
||||
res= EXIT_UNKNOWN_SUFFIX;
|
||||
goto ret;
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
|
||||
ret:
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"%s: Error while setting value '%s' to '%s'",
|
||||
my_progname, argument, opts->name);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -859,7 +934,7 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp,
|
||||
break;
|
||||
}
|
||||
|
||||
num= ((num - optp->sub_size) / block_size);
|
||||
num= (num / block_size);
|
||||
num= (longlong) (num * block_size);
|
||||
|
||||
if (num < optp->min_value)
|
||||
@@ -870,7 +945,7 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp,
|
||||
}
|
||||
|
||||
if (fix)
|
||||
*fix= adjusted;
|
||||
*fix= old != num;
|
||||
else if (adjusted)
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"option '%s': signed value %s adjusted to %s",
|
||||
@@ -942,7 +1017,7 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp,
|
||||
}
|
||||
|
||||
if (fix)
|
||||
*fix= adjusted;
|
||||
*fix= old != num;
|
||||
else if (adjusted)
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"option '%s': unsigned value %s adjusted to %s",
|
||||
@@ -951,6 +1026,29 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp,
|
||||
return num;
|
||||
}
|
||||
|
||||
double getopt_double_limit_value(double num, const struct my_option *optp,
|
||||
my_bool *fix)
|
||||
{
|
||||
my_bool adjusted= FALSE;
|
||||
double old= num;
|
||||
if (optp->max_value && num > (double) optp->max_value)
|
||||
{
|
||||
num= (double) optp->max_value;
|
||||
adjusted= TRUE;
|
||||
}
|
||||
if (num < (double) optp->min_value)
|
||||
{
|
||||
num= (double) optp->min_value;
|
||||
adjusted= TRUE;
|
||||
}
|
||||
if (fix)
|
||||
*fix= adjusted;
|
||||
else if (adjusted)
|
||||
my_getopt_error_reporter(WARNING_LEVEL,
|
||||
"option '%s': value %g adjusted to %g",
|
||||
optp->name, old, num);
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
Get double value withing ranges
|
||||
@@ -972,15 +1070,12 @@ static double getopt_double(char *arg, const struct my_option *optp, int *err)
|
||||
num= my_strtod(arg, &end, &error);
|
||||
if (end[0] != 0 || error)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: ERROR: Invalid decimal value for option '%s'\n",
|
||||
my_progname, optp->name);
|
||||
my_getopt_error_reporter(ERROR_LEVEL,
|
||||
"Invalid decimal value for option '%s'\n", optp->name);
|
||||
*err= EXIT_ARGUMENT_INVALID;
|
||||
return 0.0;
|
||||
}
|
||||
if (optp->max_value && num > (double) optp->max_value)
|
||||
num= (double) optp->max_value;
|
||||
return max(num, (double) optp->min_value);
|
||||
return getopt_double_limit_value(num, optp, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1004,7 +1099,7 @@ static void init_one_value(const struct my_option *option, void *variable,
|
||||
*((int*) variable)= (int) getopt_ll_limit_value((int) value, option, NULL);
|
||||
break;
|
||||
case GET_ENUM:
|
||||
*((uint*) variable)= (uint) value;
|
||||
*((ulong*) variable)= (ulong) value;
|
||||
break;
|
||||
case GET_UINT:
|
||||
*((uint*) variable)= (uint) getopt_ull_limit_value((uint) value, option, NULL);
|
||||
@@ -1022,10 +1117,11 @@ static void init_one_value(const struct my_option *option, void *variable,
|
||||
*((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL);
|
||||
break;
|
||||
case GET_SET:
|
||||
case GET_FLAGSET:
|
||||
*((ulonglong*) variable)= (ulonglong) value;
|
||||
break;
|
||||
case GET_DOUBLE:
|
||||
*((double*) variable)= (double) value;
|
||||
*((double*) variable)= ulonglong2double(value);
|
||||
break;
|
||||
case GET_STR:
|
||||
/*
|
||||
@@ -1046,8 +1142,9 @@ static void init_one_value(const struct my_option *option, void *variable,
|
||||
*/
|
||||
if ((char*) (intptr) value)
|
||||
{
|
||||
my_free((*(char**) variable), MYF(MY_ALLOW_ZERO_PTR));
|
||||
*((char**) variable)= my_strdup((char*) (intptr) value, MYF(MY_WME));
|
||||
char **pstr= (char **) variable;
|
||||
my_free(*pstr);
|
||||
*pstr= my_strdup((char*) (intptr) value, MYF(MY_WME));
|
||||
}
|
||||
break;
|
||||
default: /* dummy default to avoid compiler warnings */
|
||||
@@ -1072,7 +1169,7 @@ static void fini_one_value(const struct my_option *option, void *variable,
|
||||
DBUG_ENTER("fini_one_value");
|
||||
switch ((option->var_type & GET_TYPE_MASK)) {
|
||||
case GET_STR_ALLOC:
|
||||
my_free((*(char**) variable), MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(*((char**) variable));
|
||||
*((char**) variable)= NULL;
|
||||
break;
|
||||
default: /* dummy default to avoid compiler warnings */
|
||||
@@ -1097,7 +1194,7 @@ void my_cleanup_options(const struct my_option *options)
|
||||
|
||||
NOTES
|
||||
We will initialize the value that is pointed to by options->value.
|
||||
If the value is of type GET_ASK_ADDR, we will also ask for the address
|
||||
If the value is of type GET_ASK_ADDR, we will ask for the address
|
||||
for a value and initialize.
|
||||
*/
|
||||
|
||||
@@ -1107,7 +1204,7 @@ static void init_variables(const struct my_option *options,
|
||||
DBUG_ENTER("init_variables");
|
||||
for (; options->name; options++)
|
||||
{
|
||||
void *variable;
|
||||
void *value;
|
||||
DBUG_PRINT("options", ("name: '%s'", options->name));
|
||||
/*
|
||||
We must set u_max_value first as for some variables
|
||||
@@ -1116,15 +1213,22 @@ static void init_variables(const struct my_option *options,
|
||||
*/
|
||||
if (options->u_max_value)
|
||||
init_one_value(options, options->u_max_value, options->max_value);
|
||||
if (options->value)
|
||||
init_one_value(options, options->value, options->def_value);
|
||||
if (options->var_type & GET_ASK_ADDR &&
|
||||
(variable= (*getopt_get_addr)("", 0, options, 0)))
|
||||
init_one_value(options, variable, options->def_value);
|
||||
value= (options->var_type & GET_ASK_ADDR ?
|
||||
(*getopt_get_addr)("", 0, options, 0) : options->value);
|
||||
if (value)
|
||||
init_one_value(options, value, options->def_value);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/** Prints variable or option name, replacing _ with - */
|
||||
static uint print_name(const struct my_option *optp)
|
||||
{
|
||||
const char *s= optp->name;
|
||||
for (;*s;s++)
|
||||
putchar(*s == '_' ? '-' : *s);
|
||||
return s - optp->name;
|
||||
}
|
||||
|
||||
/*
|
||||
function: my_print_options
|
||||
@@ -1132,17 +1236,15 @@ static void init_variables(const struct my_option *options,
|
||||
Print help for all options and variables.
|
||||
*/
|
||||
|
||||
#include <help_start.h>
|
||||
|
||||
void my_print_help(const struct my_option *options)
|
||||
{
|
||||
uint col, name_space= 22, comment_space= 57;
|
||||
const char *line_end;
|
||||
const struct my_option *optp;
|
||||
|
||||
for (optp= options; optp->id; optp++)
|
||||
for (optp= options; optp->name; optp++)
|
||||
{
|
||||
if (optp->id < 256)
|
||||
if (optp->id && optp->id < 256)
|
||||
{
|
||||
printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " ");
|
||||
col= 6;
|
||||
@@ -1154,21 +1256,24 @@ void my_print_help(const struct my_option *options)
|
||||
}
|
||||
if (strlen(optp->name))
|
||||
{
|
||||
printf("--%s", optp->name);
|
||||
col+= 2 + (uint) strlen(optp->name);
|
||||
if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC)
|
||||
printf("--");
|
||||
col+= 2 + print_name(optp);
|
||||
if (optp->arg_type == NO_ARG ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_BOOL)
|
||||
{
|
||||
putchar(' ');
|
||||
col++;
|
||||
}
|
||||
else if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_ENUM ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_SET ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_FLAGSET )
|
||||
{
|
||||
printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
|
||||
optp->arg_type == OPT_ARG ? "]" : "");
|
||||
col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
|
||||
}
|
||||
else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
|
||||
(optp->var_type & GET_TYPE_MASK) == GET_BOOL)
|
||||
{
|
||||
putchar(' ');
|
||||
col++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "",
|
||||
@@ -1200,6 +1305,15 @@ void my_print_help(const struct my_option *options)
|
||||
printf("%s", comment);
|
||||
}
|
||||
putchar('\n');
|
||||
if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
|
||||
{
|
||||
if (optp->def_value != 0)
|
||||
{
|
||||
printf("%*s(Defaults to on; use --skip-", name_space, "");
|
||||
print_name(optp);
|
||||
printf(" to disable.)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1213,38 +1327,55 @@ void my_print_help(const struct my_option *options)
|
||||
void my_print_variables(const struct my_option *options)
|
||||
{
|
||||
uint name_space= 34, length, nr;
|
||||
ulonglong bit, llvalue;
|
||||
ulonglong llvalue;
|
||||
char buff[255];
|
||||
const struct my_option *optp;
|
||||
|
||||
for (optp= options; optp->name; optp++)
|
||||
{
|
||||
length= strlen(optp->name)+1;
|
||||
if (length > name_space)
|
||||
name_space= length;
|
||||
}
|
||||
|
||||
printf("\nVariables (--variable-name=value)\n");
|
||||
printf("and boolean options {FALSE|TRUE} Value (after reading options)\n");
|
||||
printf("--------------------------------- -----------------------------\n");
|
||||
for (optp= options; optp->id; optp++)
|
||||
printf("%-*s%s", name_space, "and boolean options {FALSE|TRUE}",
|
||||
"Value (after reading options)\n");
|
||||
for (length=1; length < 75; length++)
|
||||
putchar(length == name_space ? ' ' : '-');
|
||||
putchar('\n');
|
||||
|
||||
for (optp= options; optp->name; optp++)
|
||||
{
|
||||
void *value= (optp->var_type & GET_ASK_ADDR ?
|
||||
(*getopt_get_addr)("", 0, optp, 0) : optp->value);
|
||||
if (value)
|
||||
{
|
||||
printf("%s ", optp->name);
|
||||
length= (uint) strlen(optp->name)+1;
|
||||
length= print_name(optp);
|
||||
for (; length < name_space; length++)
|
||||
putchar(' ');
|
||||
switch ((optp->var_type & GET_TYPE_MASK)) {
|
||||
case GET_SET:
|
||||
if (!(llvalue= *(ulonglong*) value))
|
||||
printf("%s\n", "(No default value)");
|
||||
printf("%s\n", "");
|
||||
else
|
||||
for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1)
|
||||
for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
|
||||
{
|
||||
if (!(bit & llvalue))
|
||||
continue;
|
||||
llvalue&= ~bit;
|
||||
printf( llvalue ? "%s," : "%s\n", get_type(optp->typelib, nr));
|
||||
if (llvalue & 1)
|
||||
printf( llvalue > 1 ? "%s," : "%s\n", get_type(optp->typelib, nr));
|
||||
}
|
||||
break;
|
||||
case GET_FLAGSET:
|
||||
llvalue= *(ulonglong*) value;
|
||||
for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
|
||||
{
|
||||
printf("%s%s=", (nr ? "," : ""), get_type(optp->typelib, nr));
|
||||
printf(llvalue & 1 ? "on" : "off");
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
case GET_ENUM:
|
||||
printf("%s\n", get_type(optp->typelib, *(uint*) value));
|
||||
printf("%s\n", get_type(optp->typelib, *(ulong*) value));
|
||||
break;
|
||||
case GET_STR:
|
||||
case GET_STR_ALLOC: /* fall through */
|
||||
@@ -1276,6 +1407,9 @@ void my_print_variables(const struct my_option *options)
|
||||
case GET_DOUBLE:
|
||||
printf("%g\n", *(double*) value);
|
||||
break;
|
||||
case GET_NO_ARG:
|
||||
printf("(No default value)\n");
|
||||
break;
|
||||
default:
|
||||
printf("(Disabled)\n");
|
||||
break;
|
||||
@@ -1283,5 +1417,3 @@ void my_print_variables(const struct my_option *options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <help_end.h>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
|
||||
#if defined __WIN__
|
||||
|
||||
int my_getpagesize(void)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Default implementation */
|
||||
int my_getpagesize(void)
|
||||
{
|
||||
return (int)8192;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2004 MySQL AB
|
||||
/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -25,10 +25,6 @@
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
|
||||
#ifdef __NETWARE__
|
||||
#include <nks/time.h>
|
||||
#endif
|
||||
|
||||
ulonglong my_getsystime()
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
@@ -45,10 +41,6 @@ ulonglong my_getsystime()
|
||||
query_performance_frequency) + query_performance_offset);
|
||||
}
|
||||
return 0;
|
||||
#elif defined(__NETWARE__)
|
||||
NXTime_t tm;
|
||||
NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm);
|
||||
return (ulonglong)tm/100;
|
||||
#else
|
||||
/* TODO: check for other possibilities for hi-res timestamping */
|
||||
struct timeval tv;
|
||||
@@ -150,7 +142,10 @@ ulonglong my_micro_time()
|
||||
Value in microseconds from some undefined point in time
|
||||
*/
|
||||
|
||||
#define DELTA_FOR_SECONDS LL(500000000) /* Half a second */
|
||||
#define DELTA_FOR_SECONDS 500000000LL /* Half a second */
|
||||
|
||||
/* Difference between GetSystemTimeAsFileTime() and now() */
|
||||
#define OFFSET_TO_EPOCH 116444736000000000ULL
|
||||
|
||||
ulonglong my_micro_time_and_time(time_t *time_arg)
|
||||
{
|
||||
@@ -168,15 +163,21 @@ ulonglong my_micro_time_and_time(time_t *time_arg)
|
||||
static time_t cur_time= 0;
|
||||
hrtime_t cur_gethrtime;
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_time);
|
||||
mysql_mutex_lock(&THR_LOCK_time);
|
||||
cur_gethrtime= gethrtime();
|
||||
if ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS)
|
||||
/*
|
||||
Due to bugs in the Solaris (x86) implementation of gethrtime(),
|
||||
the time returned by it might not be monotonic. Don't use the
|
||||
cached time(2) value if this is a case.
|
||||
*/
|
||||
if ((prev_gethrtime > cur_gethrtime) ||
|
||||
((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS))
|
||||
{
|
||||
cur_time= time(0);
|
||||
prev_gethrtime= cur_gethrtime;
|
||||
}
|
||||
*time_arg= cur_time;
|
||||
pthread_mutex_unlock(&THR_LOCK_time);
|
||||
mysql_mutex_unlock(&THR_LOCK_time);
|
||||
return cur_gethrtime/1000;
|
||||
#else
|
||||
ulonglong newtime;
|
||||
|
||||
@@ -51,20 +51,20 @@ int my_getwd(char * buf, size_t size, myf MyFlags)
|
||||
(long) buf, (uint) size, MyFlags));
|
||||
|
||||
if (size < 1)
|
||||
return(-1);
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (curr_dir[0]) /* Current pos is saved here */
|
||||
VOID(strmake(buf,&curr_dir[0],size-1));
|
||||
(void) strmake(buf,&curr_dir[0],size-1);
|
||||
else
|
||||
{
|
||||
#if defined(HAVE_GETCWD)
|
||||
if (size < 2)
|
||||
return(-1);
|
||||
DBUG_RETURN(-1);
|
||||
if (!getcwd(buf,(uint) (size-2)) && MyFlags & MY_WME)
|
||||
{
|
||||
my_errno=errno;
|
||||
my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
|
||||
return(-1);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#elif defined(HAVE_GETWD)
|
||||
{
|
||||
@@ -72,16 +72,6 @@ int my_getwd(char * buf, size_t size, myf MyFlags)
|
||||
getwd(pathname);
|
||||
strmake(buf,pathname,size-1);
|
||||
}
|
||||
#elif defined(VMS)
|
||||
if (size < 2)
|
||||
return(-1);
|
||||
if (!getcwd(buf,size-2,1) && MyFlags & MY_WME)
|
||||
{
|
||||
my_errno=errno;
|
||||
my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
|
||||
return(-1);
|
||||
}
|
||||
intern_filename(buf,buf);
|
||||
#else
|
||||
#error "No way to get current directory"
|
||||
#endif
|
||||
@@ -103,27 +93,12 @@ int my_setwd(const char *dir, myf MyFlags)
|
||||
int res;
|
||||
size_t length;
|
||||
char *start, *pos;
|
||||
#if defined(VMS)
|
||||
char buff[FN_REFLEN];
|
||||
#endif
|
||||
DBUG_ENTER("my_setwd");
|
||||
DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
|
||||
|
||||
start=(char *) dir;
|
||||
if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
|
||||
dir=FN_ROOTDIR;
|
||||
#ifdef VMS
|
||||
{
|
||||
pos=strmov(buff,dir);
|
||||
if (pos[-1] != FN_LIBCHAR)
|
||||
{
|
||||
pos[0]=FN_LIBCHAR; /* Mark as directory */
|
||||
pos[1]=0;
|
||||
}
|
||||
system_filename(buff,buff); /* Change to VMS format */
|
||||
dir=buff;
|
||||
}
|
||||
#endif /* VMS */
|
||||
if ((res=chdir((char*) dir)) != 0)
|
||||
{
|
||||
my_errno=errno;
|
||||
|
||||
@@ -0,0 +1,604 @@
|
||||
/* Copyright (C) 2002-2006 MySQL AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; version 2
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_ctype.h>
|
||||
#include <my_base.h>
|
||||
#include <my_handler.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include "my_handler_errors.h"
|
||||
|
||||
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
|
||||
|
||||
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
|
||||
uchar *b, uint b_length, my_bool part_key,
|
||||
my_bool skip_end_space)
|
||||
{
|
||||
if (!part_key)
|
||||
return charset_info->coll->strnncollsp(charset_info, a, a_length,
|
||||
b, b_length, (my_bool)!skip_end_space);
|
||||
return charset_info->coll->strnncoll(charset_info, a, a_length,
|
||||
b, b_length, part_key);
|
||||
}
|
||||
|
||||
|
||||
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
|
||||
my_bool part_key, my_bool skip_end_space)
|
||||
{
|
||||
uint length= min(a_length,b_length);
|
||||
uchar *end= a+ length;
|
||||
int flag;
|
||||
|
||||
while (a < end)
|
||||
if ((flag= (int) *a++ - (int) *b++))
|
||||
return flag;
|
||||
if (part_key && b_length < a_length)
|
||||
return 0;
|
||||
if (skip_end_space && a_length != b_length)
|
||||
{
|
||||
int swap= 1;
|
||||
/*
|
||||
We are using space compression. We have to check if longer key
|
||||
has next character < ' ', in which case it's less than the shorter
|
||||
key that has an implicite space afterwards.
|
||||
|
||||
This code is identical to the one in
|
||||
strings/ctype-simple.c:my_strnncollsp_simple
|
||||
*/
|
||||
if (a_length < b_length)
|
||||
{
|
||||
/* put shorter key in a */
|
||||
a_length= b_length;
|
||||
a= b;
|
||||
swap= -1; /* swap sign of result */
|
||||
}
|
||||
for (end= a + a_length-length; a < end ; a++)
|
||||
{
|
||||
if (*a != ' ')
|
||||
return (*a < ' ') ? -swap : swap;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return (int) (a_length-b_length);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compare two keys
|
||||
|
||||
SYNOPSIS
|
||||
ha_key_cmp()
|
||||
keyseg Array of key segments of key to compare
|
||||
a First key to compare, in format from _mi_pack_key()
|
||||
This is normally key specified by user
|
||||
b Second key to compare. This is always from a row
|
||||
key_length Length of key to compare. This can be shorter than
|
||||
a to just compare sub keys
|
||||
next_flag How keys should be compared
|
||||
If bit SEARCH_FIND is not set the keys includes the row
|
||||
position and this should also be compared
|
||||
diff_pos OUT Number of first keypart where values differ, counting
|
||||
from one.
|
||||
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
|
||||
that is different from corresponding value in tuple a.
|
||||
|
||||
EXAMPLES
|
||||
Example1: if the function is called for tuples
|
||||
('aaa','bbb') and ('eee','fff'), then
|
||||
diff_pos[0] = 1 (as 'aaa' != 'eee')
|
||||
diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
|
||||
|
||||
Example2: if the index function is called for tuples
|
||||
('aaa','bbb') and ('aaa','fff'),
|
||||
diff_pos[0] = 2 (as 'aaa' != 'eee')
|
||||
diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
|
||||
here we assume that first key part is CHAR(3) NOT NULL)
|
||||
|
||||
NOTES
|
||||
Number-keys can't be splited
|
||||
|
||||
RETURN VALUES
|
||||
<0 If a < b
|
||||
0 If a == b
|
||||
>0 If a > b
|
||||
*/
|
||||
|
||||
#define FCMP(A,B) ((int) (A) - (int) (B))
|
||||
|
||||
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
|
||||
register uchar *b, uint key_length, uint nextflag,
|
||||
uint *diff_pos)
|
||||
{
|
||||
int flag;
|
||||
int16 s_1,s_2;
|
||||
int32 l_1,l_2;
|
||||
uint32 u_1,u_2;
|
||||
float f_1,f_2;
|
||||
double d_1,d_2;
|
||||
uint next_key_length;
|
||||
uchar *orig_b= b;
|
||||
|
||||
*diff_pos=0;
|
||||
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
|
||||
{
|
||||
uchar *end;
|
||||
uint piks=! (keyseg->flag & HA_NO_SORT);
|
||||
(*diff_pos)++;
|
||||
diff_pos[1]= (uint)(b - orig_b);
|
||||
|
||||
/* Handle NULL part */
|
||||
if (keyseg->null_bit)
|
||||
{
|
||||
key_length--;
|
||||
if (*a != *b && piks)
|
||||
{
|
||||
flag = (int) *a - (int) *b;
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
}
|
||||
b++;
|
||||
if (!*a++) /* If key was NULL */
|
||||
{
|
||||
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
|
||||
nextflag=SEARCH_SAME; /* Allow duplicate keys */
|
||||
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
|
||||
{
|
||||
/*
|
||||
This is only used from mi_check() to calculate cardinality.
|
||||
It can't be used when searching for a key as this would cause
|
||||
compare of (a,b) and (b,a) to return the same value.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
next_key_length=key_length;
|
||||
continue; /* To next key part */
|
||||
}
|
||||
}
|
||||
end= a+ min(keyseg->length,key_length);
|
||||
next_key_length=key_length-keyseg->length;
|
||||
|
||||
switch ((enum ha_base_keytype) keyseg->type) {
|
||||
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint length=(uint) (end-a), a_length=length, b_length=length;
|
||||
if (piks &&
|
||||
(flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a=end;
|
||||
b+=length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_BINARY:
|
||||
case HA_KEYTYPE_BIT:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),1)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint length=keyseg->length;
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,length,b,length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),0)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=length;
|
||||
b+=length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_VARTEXT1:
|
||||
case HA_KEYTYPE_VARTEXT2:
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0),
|
||||
(my_bool) ((nextflag & (SEARCH_FIND |
|
||||
SEARCH_UPDATE)) ==
|
||||
SEARCH_FIND &&
|
||||
! (keyseg->flag &
|
||||
HA_END_SPACE_ARE_EQUAL)))))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+= a_length;
|
||||
b+= b_length;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_VARBINARY1:
|
||||
case HA_KEYTYPE_VARBINARY2:
|
||||
{
|
||||
int a_length,b_length,pack_length;
|
||||
get_key_length(a_length,a);
|
||||
get_key_pack_length(b_length,pack_length,b);
|
||||
next_key_length=key_length-b_length-pack_length;
|
||||
|
||||
if (piks &&
|
||||
(flag=compare_bin(a,a_length,b,b_length,
|
||||
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
||||
next_key_length <= 0), 0)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a+=a_length;
|
||||
b+=b_length;
|
||||
}
|
||||
break;
|
||||
case HA_KEYTYPE_INT8:
|
||||
{
|
||||
int i_1= (int) *((signed char*) a);
|
||||
int i_2= (int) *((signed char*) b);
|
||||
if (piks && (flag = CMP_NUM(i_1,i_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b++;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_SHORT_INT:
|
||||
s_1= mi_sint2korr(a);
|
||||
s_2= mi_sint2korr(b);
|
||||
if (piks && (flag = CMP_NUM(s_1,s_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 2; /* sizeof(short int); */
|
||||
break;
|
||||
case HA_KEYTYPE_USHORT_INT:
|
||||
{
|
||||
uint16 us_1,us_2;
|
||||
us_1= mi_sint2korr(a);
|
||||
us_2= mi_sint2korr(b);
|
||||
if (piks && (flag = CMP_NUM(us_1,us_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+=2; /* sizeof(short int); */
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_LONG_INT:
|
||||
l_1= mi_sint4korr(a);
|
||||
l_2= mi_sint4korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(long int); */
|
||||
break;
|
||||
case HA_KEYTYPE_ULONG_INT:
|
||||
u_1= mi_sint4korr(a);
|
||||
u_2= mi_sint4korr(b);
|
||||
if (piks && (flag = CMP_NUM(u_1,u_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(long int); */
|
||||
break;
|
||||
case HA_KEYTYPE_INT24:
|
||||
l_1=mi_sint3korr(a);
|
||||
l_2=mi_sint3korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 3;
|
||||
break;
|
||||
case HA_KEYTYPE_UINT24:
|
||||
l_1=mi_uint3korr(a);
|
||||
l_2=mi_uint3korr(b);
|
||||
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 3;
|
||||
break;
|
||||
case HA_KEYTYPE_FLOAT:
|
||||
mi_float4get(f_1,a);
|
||||
mi_float4get(f_2,b);
|
||||
/*
|
||||
The following may give a compiler warning about floating point
|
||||
comparison not being safe, but this is ok in this context as
|
||||
we are bascily doing sorting
|
||||
*/
|
||||
if (piks && (flag = CMP_NUM(f_1,f_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 4; /* sizeof(float); */
|
||||
break;
|
||||
case HA_KEYTYPE_DOUBLE:
|
||||
mi_float8get(d_1,a);
|
||||
mi_float8get(d_2,b);
|
||||
/*
|
||||
The following may give a compiler warning about floating point
|
||||
comparison not being safe, but this is ok in this context as
|
||||
we are bascily doing sorting
|
||||
*/
|
||||
if (piks && (flag = CMP_NUM(d_1,d_2)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8; /* sizeof(double); */
|
||||
break;
|
||||
case HA_KEYTYPE_NUM: /* Numeric key */
|
||||
{
|
||||
int swap_flag= 0;
|
||||
int alength,blength;
|
||||
|
||||
if (keyseg->flag & HA_REVERSE_SORT)
|
||||
{
|
||||
swap_variables(uchar*, a, b);
|
||||
swap_flag=1; /* Remember swap of a & b */
|
||||
end= a+ (int) (end-b);
|
||||
}
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
alength= *a++; blength= *b++;
|
||||
end=a+alength;
|
||||
next_key_length=key_length-blength-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alength= (int) (end-a);
|
||||
blength=keyseg->length;
|
||||
/* remove pre space from keys */
|
||||
for ( ; alength && *a == ' ' ; a++, alength--) ;
|
||||
for ( ; blength && *b == ' ' ; b++, blength--) ;
|
||||
}
|
||||
if (piks)
|
||||
{
|
||||
if (*a == '-')
|
||||
{
|
||||
if (*b != '-')
|
||||
return -1;
|
||||
a++; b++;
|
||||
swap_variables(uchar*, a, b);
|
||||
swap_variables(int, alength, blength);
|
||||
swap_flag=1-swap_flag;
|
||||
alength--; blength--;
|
||||
end=a+alength;
|
||||
}
|
||||
else if (*b == '-')
|
||||
return 1;
|
||||
while (alength && (*a == '+' || *a == '0'))
|
||||
{
|
||||
a++; alength--;
|
||||
}
|
||||
while (blength && (*b == '+' || *b == '0'))
|
||||
{
|
||||
b++; blength--;
|
||||
}
|
||||
if (alength != blength)
|
||||
return (alength < blength) ? -1 : 1;
|
||||
while (a < end)
|
||||
if (*a++ != *b++)
|
||||
return ((int) a[-1] - (int) b[-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
b+=(end-a);
|
||||
a=end;
|
||||
}
|
||||
|
||||
if (swap_flag) /* Restore pointers */
|
||||
swap_variables(uchar*, a, b);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case HA_KEYTYPE_LONGLONG:
|
||||
{
|
||||
longlong ll_a,ll_b;
|
||||
ll_a= mi_sint8korr(a);
|
||||
ll_b= mi_sint8korr(b);
|
||||
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_ULONGLONG:
|
||||
{
|
||||
ulonglong ll_a,ll_b;
|
||||
ll_a= mi_uint8korr(a);
|
||||
ll_b= mi_uint8korr(b);
|
||||
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
||||
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
||||
a= end;
|
||||
b+= 8;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case HA_KEYTYPE_END: /* Ready */
|
||||
goto end; /* diff_pos is incremented */
|
||||
}
|
||||
}
|
||||
(*diff_pos)++;
|
||||
end:
|
||||
if (!(nextflag & SEARCH_FIND))
|
||||
{
|
||||
uint i;
|
||||
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
|
||||
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
|
||||
flag=0;
|
||||
for (i=keyseg->length ; i-- > 0 ; )
|
||||
{
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
flag= FCMP(a[-1],b[-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextflag & SEARCH_SAME)
|
||||
return (flag); /* read same */
|
||||
if (nextflag & SEARCH_BIGGER)
|
||||
return (flag <= 0 ? -1 : 1); /* read next */
|
||||
return (flag < 0 ? -1 : 1); /* read previous */
|
||||
}
|
||||
return 0;
|
||||
} /* ha_key_cmp */
|
||||
|
||||
|
||||
/*
|
||||
Find the first NULL value in index-suffix values tuple
|
||||
|
||||
SYNOPSIS
|
||||
ha_find_null()
|
||||
keyseg Array of keyparts for key suffix
|
||||
a Key suffix value tuple
|
||||
|
||||
DESCRIPTION
|
||||
Find the first NULL value in index-suffix values tuple.
|
||||
|
||||
TODO
|
||||
Consider optimizing this function or its use so we don't search for
|
||||
NULL values in completely NOT NULL index suffixes.
|
||||
|
||||
RETURN
|
||||
First key part that has NULL as value in values tuple, or the last key
|
||||
part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
|
||||
NULLs.
|
||||
*/
|
||||
|
||||
HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
|
||||
{
|
||||
for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
|
||||
{
|
||||
uchar *end;
|
||||
if (keyseg->null_bit)
|
||||
{
|
||||
if (!*a++)
|
||||
return keyseg;
|
||||
}
|
||||
end= a+ keyseg->length;
|
||||
|
||||
switch ((enum ha_base_keytype) keyseg->type) {
|
||||
case HA_KEYTYPE_TEXT:
|
||||
case HA_KEYTYPE_BINARY:
|
||||
case HA_KEYTYPE_BIT:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int a_length;
|
||||
get_key_length(a_length, a);
|
||||
a += a_length;
|
||||
break;
|
||||
}
|
||||
else
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_VARTEXT1:
|
||||
case HA_KEYTYPE_VARTEXT2:
|
||||
case HA_KEYTYPE_VARBINARY1:
|
||||
case HA_KEYTYPE_VARBINARY2:
|
||||
{
|
||||
int a_length;
|
||||
get_key_length(a_length, a);
|
||||
a+= a_length;
|
||||
break;
|
||||
}
|
||||
case HA_KEYTYPE_NUM:
|
||||
if (keyseg->flag & HA_SPACE_PACK)
|
||||
{
|
||||
int alength= *a++;
|
||||
end= a+alength;
|
||||
}
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_INT8:
|
||||
case HA_KEYTYPE_SHORT_INT:
|
||||
case HA_KEYTYPE_USHORT_INT:
|
||||
case HA_KEYTYPE_LONG_INT:
|
||||
case HA_KEYTYPE_ULONG_INT:
|
||||
case HA_KEYTYPE_INT24:
|
||||
case HA_KEYTYPE_UINT24:
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case HA_KEYTYPE_LONGLONG:
|
||||
case HA_KEYTYPE_ULONGLONG:
|
||||
#endif
|
||||
case HA_KEYTYPE_FLOAT:
|
||||
case HA_KEYTYPE_DOUBLE:
|
||||
a= end;
|
||||
break;
|
||||
case HA_KEYTYPE_END: /* purecov: inspected */
|
||||
/* keep compiler happy */
|
||||
DBUG_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return keyseg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Register handler error messages for usage with my_error()
|
||||
|
||||
NOTES
|
||||
This is safe to call multiple times as my_error_register()
|
||||
will ignore calls to register already registered error numbers.
|
||||
*/
|
||||
|
||||
static const char **get_handler_error_messages()
|
||||
{
|
||||
return handler_error_messages;
|
||||
}
|
||||
|
||||
void my_handler_error_register(void)
|
||||
{
|
||||
/*
|
||||
If you got compilation error here about compile_time_assert array, check
|
||||
that every HA_ERR_xxx constant has a corresponding error message in
|
||||
handler_error_messages[] list (check mysys/ma_handler_errors.h and
|
||||
include/my_base.h).
|
||||
*/
|
||||
compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
|
||||
HA_ERR_LAST + 1);
|
||||
my_error_register(get_handler_error_messages, HA_ERR_FIRST,
|
||||
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
||||
}
|
||||
|
||||
|
||||
void my_handler_error_unregister(void)
|
||||
{
|
||||
my_error_unregister(HA_ERR_FIRST,
|
||||
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#ifndef MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
#define MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
|
||||
/*
|
||||
Errors a handler can give you
|
||||
@@ -66,3 +68,4 @@ static const char *handler_error_messages[]=
|
||||
"Too many active concurrent transactions"
|
||||
};
|
||||
|
||||
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
|
||||
|
||||
+281
-212
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,14 +19,12 @@
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#include <signal.h>
|
||||
#ifdef VMS
|
||||
#include <my_static.c>
|
||||
#include <m_ctype.h>
|
||||
#endif
|
||||
#ifdef __WIN__
|
||||
#ifdef _MSC_VER
|
||||
#include <locale.h>
|
||||
#include <crtdbg.h>
|
||||
/* WSAStartup needs winsock library*/
|
||||
#pragma comment(lib, "ws2_32")
|
||||
#endif
|
||||
my_bool have_tcpip=0;
|
||||
static void my_win_init(void);
|
||||
@@ -34,13 +32,13 @@ static my_bool win32_init_tcp_ip();
|
||||
#else
|
||||
#define my_win_init()
|
||||
#endif
|
||||
#ifdef __NETWARE__
|
||||
static void netware_init();
|
||||
#else
|
||||
#define netware_init()
|
||||
#endif
|
||||
|
||||
#define SCALE_SEC 100
|
||||
#define SCALE_USEC 10000
|
||||
|
||||
my_bool my_init_done= 0;
|
||||
/** True if @c my_basic_init() has been called. */
|
||||
my_bool my_basic_init_done= 0;
|
||||
uint mysys_usage_id= 0; /* Incremented for each my_init() */
|
||||
ulong my_thread_stack_size= 65536;
|
||||
|
||||
@@ -55,6 +53,68 @@ static ulong atoi_octal(const char *str)
|
||||
return (ulong) tmp;
|
||||
}
|
||||
|
||||
MYSQL_FILE *mysql_stdin= NULL;
|
||||
static MYSQL_FILE instrumented_stdin;
|
||||
|
||||
/**
|
||||
Perform a limited initialisation of mysys.
|
||||
This initialisation is sufficient to:
|
||||
- allocate memory,
|
||||
- read configuration files,
|
||||
- parse command lines arguments.
|
||||
To complete the mysys initialisation,
|
||||
call my_init().
|
||||
@return 0 on success
|
||||
*/
|
||||
my_bool my_basic_init(void)
|
||||
{
|
||||
char * str;
|
||||
|
||||
if (my_basic_init_done)
|
||||
return 0;
|
||||
my_basic_init_done= 1;
|
||||
|
||||
mysys_usage_id++;
|
||||
my_umask= 0660; /* Default umask for new files */
|
||||
my_umask_dir= 0700; /* Default umask for new directories */
|
||||
|
||||
/* Default creation of new files */
|
||||
if ((str= getenv("UMASK")) != 0)
|
||||
my_umask= (int) (atoi_octal(str) | 0600);
|
||||
/* Default creation of new dir's */
|
||||
if ((str= getenv("UMASK_DIR")) != 0)
|
||||
my_umask_dir= (int) (atoi_octal(str) | 0700);
|
||||
|
||||
init_glob_errs();
|
||||
|
||||
instrumented_stdin.m_file= stdin;
|
||||
instrumented_stdin.m_psi= NULL; /* not yet instrumented */
|
||||
mysql_stdin= & instrumented_stdin;
|
||||
|
||||
if (my_thread_global_init())
|
||||
return 1;
|
||||
|
||||
#if defined(SAFE_MUTEX)
|
||||
safe_mutex_global_init(); /* Must be called early */
|
||||
#endif
|
||||
|
||||
#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
|
||||
fastmutex_global_init(); /* Must be called early */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_INIT)
|
||||
pthread_init(); /* Must be called before DBUG_ENTER */
|
||||
#endif
|
||||
if (my_thread_basic_global_init())
|
||||
return 1;
|
||||
|
||||
/* $HOME is needed early to parse configuration files located in ~/ */
|
||||
if ((home_dir= getenv("HOME")) != 0)
|
||||
home_dir= intern_filename(home_dir_buff, home_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Init my_sys functions and my_sys variabels
|
||||
@@ -69,54 +129,22 @@ static ulong atoi_octal(const char *str)
|
||||
|
||||
my_bool my_init(void)
|
||||
{
|
||||
char * str;
|
||||
if (my_init_done)
|
||||
return 0;
|
||||
my_init_done=1;
|
||||
mysys_usage_id++;
|
||||
my_umask= 0660; /* Default umask for new files */
|
||||
my_umask_dir= 0700; /* Default umask for new directories */
|
||||
init_glob_errs();
|
||||
#if defined(THREAD)
|
||||
|
||||
my_init_done= 1;
|
||||
|
||||
if (my_basic_init())
|
||||
return 1;
|
||||
|
||||
if (my_thread_global_init())
|
||||
return 1;
|
||||
# if defined(SAFE_MUTEX)
|
||||
safe_mutex_global_init(); /* Must be called early */
|
||||
# endif
|
||||
#endif
|
||||
#if defined(THREAD) && defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
|
||||
fastmutex_global_init(); /* Must be called early */
|
||||
#endif
|
||||
netware_init();
|
||||
#ifdef THREAD
|
||||
#if defined(HAVE_PTHREAD_INIT)
|
||||
pthread_init(); /* Must be called before DBUG_ENTER */
|
||||
#endif
|
||||
#if !defined( __WIN__) && !defined(__NETWARE__)
|
||||
sigfillset(&my_signals); /* signals blocked by mf_brkhant */
|
||||
#endif
|
||||
#endif /* THREAD */
|
||||
|
||||
{
|
||||
DBUG_ENTER("my_init");
|
||||
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
|
||||
if (!home_dir)
|
||||
{ /* Don't initialize twice */
|
||||
my_win_init();
|
||||
if ((home_dir=getenv("HOME")) != 0)
|
||||
home_dir=intern_filename(home_dir_buff,home_dir);
|
||||
#ifndef VMS
|
||||
/* Default creation of new files */
|
||||
if ((str=getenv("UMASK")) != 0)
|
||||
my_umask=(int) (atoi_octal(str) | 0600);
|
||||
/* Default creation of new dir's */
|
||||
if ((str=getenv("UMASK_DIR")) != 0)
|
||||
my_umask_dir=(int) (atoi_octal(str) | 0700);
|
||||
#endif
|
||||
#ifdef VMS
|
||||
init_ctype(); /* Stupid linker don't link _ctype.c */
|
||||
#endif
|
||||
DBUG_PRINT("exit",("home: '%s'",home_dir));
|
||||
}
|
||||
my_win_init();
|
||||
DBUG_PRINT("exit", ("home: '%s'", home_dir));
|
||||
#ifdef __WIN__
|
||||
win32_init_tcp_ip();
|
||||
#endif
|
||||
@@ -160,7 +188,7 @@ void my_end(int infoflag)
|
||||
char ebuff[512];
|
||||
my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING),
|
||||
my_file_opened, my_stream_opened);
|
||||
my_message_no_curses(EE_OPEN_WARNING, ebuff, ME_BELL);
|
||||
my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL);
|
||||
DBUG_PRINT("error", ("%s", ebuff));
|
||||
my_print_open_files();
|
||||
}
|
||||
@@ -194,12 +222,7 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
|
||||
rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
|
||||
rus.ru_nvcsw, rus.ru_nivcsw);
|
||||
#endif
|
||||
#if defined(__NETWARE__) && !defined(__WIN__)
|
||||
fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
|
||||
#endif
|
||||
#if defined(SAFEMALLOC)
|
||||
TERMINATE(stderr, (infoflag & MY_GIVE_INFO) != 0);
|
||||
#elif defined(__WIN__) && defined(_MSC_VER)
|
||||
#if defined(__WIN__) && defined(_MSC_VER)
|
||||
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
|
||||
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
|
||||
@@ -210,16 +233,12 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
}
|
||||
else if (infoflag & MY_CHECK_ERROR)
|
||||
{
|
||||
TERMINATE(stderr, 0); /* Print memory leaks on screen */
|
||||
}
|
||||
|
||||
if (!(infoflag & MY_DONT_FREE_DBUG))
|
||||
{
|
||||
DBUG_END(); /* Must be done before my_thread_end */
|
||||
}
|
||||
#ifdef THREAD
|
||||
|
||||
my_thread_end();
|
||||
my_thread_global_end();
|
||||
#if defined(SAFE_MUTEX)
|
||||
@@ -230,13 +249,14 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
|
||||
safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
|
||||
(FILE *) 0);
|
||||
#endif /* defined(SAFE_MUTEX) */
|
||||
#endif /* THREAD */
|
||||
|
||||
#ifdef __WIN__
|
||||
if (have_tcpip)
|
||||
WSACleanup();
|
||||
#endif /* __WIN__ */
|
||||
|
||||
my_init_done=0;
|
||||
my_basic_init_done= 0;
|
||||
} /* my_end */
|
||||
|
||||
|
||||
@@ -288,6 +308,89 @@ int handle_rtc_failure(int err_type, const char *file, int line,
|
||||
#pragma runtime_checks("", restore)
|
||||
#endif
|
||||
|
||||
#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
|
||||
#define MS 10000000
|
||||
|
||||
static void win_init_time(void)
|
||||
{
|
||||
/* The following is used by time functions */
|
||||
FILETIME ft;
|
||||
LARGE_INTEGER li, t_cnt;
|
||||
|
||||
DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));
|
||||
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
|
||||
query_performance_frequency= 0;
|
||||
else
|
||||
{
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
li.LowPart= ft.dwLowDateTime;
|
||||
li.HighPart= ft.dwHighDateTime;
|
||||
query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
|
||||
QueryPerformanceCounter(&t_cnt);
|
||||
query_performance_offset-= (t_cnt.QuadPart /
|
||||
query_performance_frequency * MS +
|
||||
t_cnt.QuadPart %
|
||||
query_performance_frequency * MS /
|
||||
query_performance_frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open HKEY_LOCAL_MACHINE\SOFTWARE\MySQL and set any strings found
|
||||
there as environment variables
|
||||
*/
|
||||
static void win_init_registry(void)
|
||||
{
|
||||
HKEY key_handle;
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)"SOFTWARE\\MySQL",
|
||||
0, KEY_READ, &key_handle) == ERROR_SUCCESS)
|
||||
{
|
||||
LONG ret;
|
||||
DWORD index= 0;
|
||||
DWORD type;
|
||||
char key_name[256], key_data[1024];
|
||||
DWORD key_name_len= sizeof(key_name) - 1;
|
||||
DWORD key_data_len= sizeof(key_data) - 1;
|
||||
|
||||
while ((ret= RegEnumValue(key_handle, index++,
|
||||
key_name, &key_name_len,
|
||||
NULL, &type, (LPBYTE)&key_data,
|
||||
&key_data_len)) != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
char env_string[sizeof(key_name) + sizeof(key_data) + 2];
|
||||
|
||||
if (ret == ERROR_MORE_DATA)
|
||||
{
|
||||
/* Registry value larger than 'key_data', skip it */
|
||||
DBUG_PRINT("error", ("Skipped registry value that was too large"));
|
||||
}
|
||||
else if (ret == ERROR_SUCCESS)
|
||||
{
|
||||
if (type == REG_SZ)
|
||||
{
|
||||
strxmov(env_string, key_name, "=", key_data, NullS);
|
||||
|
||||
/* variable for putenv must be allocated ! */
|
||||
putenv(strdup(env_string)) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unhandled error, break out of loop */
|
||||
break;
|
||||
}
|
||||
|
||||
key_name_len= sizeof(key_name) - 1;
|
||||
key_data_len= sizeof(key_data) - 1;
|
||||
}
|
||||
|
||||
RegCloseKey(key_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void my_win_init(void)
|
||||
{
|
||||
@@ -295,17 +398,18 @@ static void my_win_init(void)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER < 1300
|
||||
/*
|
||||
/*
|
||||
Clear the OS system variable TZ and avoid the 100% CPU usage
|
||||
Only for old versions of Visual C++
|
||||
*/
|
||||
_putenv( "TZ=" );
|
||||
#endif
|
||||
_putenv("TZ=");
|
||||
#endif
|
||||
#if _MSC_VER >= 1400
|
||||
/* this is required to make crt functions return -1 appropriately */
|
||||
_set_invalid_parameter_handler(my_parameter_handler);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __MSVC_RUNTIME_CHECKS
|
||||
/*
|
||||
Install handler to send RTC (Runtime Error Check) warnings
|
||||
@@ -316,106 +420,10 @@ static void my_win_init(void)
|
||||
|
||||
_tzset();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The following is used by time functions */
|
||||
#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
|
||||
#define MS 10000000
|
||||
{
|
||||
FILETIME ft;
|
||||
LARGE_INTEGER li, t_cnt;
|
||||
DBUG_ASSERT(sizeof(LARGE_INTEGER) == sizeof(query_performance_frequency));
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER *)&query_performance_frequency) == 0)
|
||||
query_performance_frequency= 0;
|
||||
else
|
||||
{
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
li.LowPart= ft.dwLowDateTime;
|
||||
li.HighPart= ft.dwHighDateTime;
|
||||
query_performance_offset= li.QuadPart-OFFSET_TO_EPOC;
|
||||
QueryPerformanceCounter(&t_cnt);
|
||||
query_performance_offset-= (t_cnt.QuadPart /
|
||||
query_performance_frequency * MS +
|
||||
t_cnt.QuadPart %
|
||||
query_performance_frequency * MS /
|
||||
query_performance_frequency);
|
||||
}
|
||||
}
|
||||
win_init_time();
|
||||
win_init_registry();
|
||||
|
||||
{
|
||||
/*
|
||||
Open HKEY_LOCAL_MACHINE\SOFTWARE\MySQL and set any strings found
|
||||
there as environment variables
|
||||
*/
|
||||
HKEY key_handle;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)"SOFTWARE\\MySQL",
|
||||
0, KEY_READ, &key_handle) == ERROR_SUCCESS)
|
||||
{
|
||||
LONG ret;
|
||||
DWORD index= 0;
|
||||
DWORD type;
|
||||
char key_name[256], key_data[1024];
|
||||
DWORD key_name_len= sizeof(key_name) - 1;
|
||||
DWORD key_data_len= sizeof(key_data) - 1;
|
||||
|
||||
while ((ret= RegEnumValue(key_handle, index++,
|
||||
key_name, &key_name_len,
|
||||
NULL, &type, (LPBYTE)&key_data,
|
||||
&key_data_len)) != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
char env_string[sizeof(key_name) + sizeof(key_data) + 2];
|
||||
|
||||
if (ret == ERROR_MORE_DATA)
|
||||
{
|
||||
/* Registry value larger than 'key_data', skip it */
|
||||
DBUG_PRINT("error", ("Skipped registry value that was too large"));
|
||||
}
|
||||
else if (ret == ERROR_SUCCESS)
|
||||
{
|
||||
if (type == REG_SZ)
|
||||
{
|
||||
strxmov(env_string, key_name, "=", key_data, NullS);
|
||||
|
||||
/* variable for putenv must be allocated ! */
|
||||
putenv(strdup(env_string)) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unhandled error, break out of loop */
|
||||
break;
|
||||
}
|
||||
|
||||
key_name_len= sizeof(key_name) - 1;
|
||||
key_data_len= sizeof(key_data) - 1;
|
||||
}
|
||||
|
||||
RegCloseKey(key_handle) ;
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN ;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,7 +462,7 @@ static my_bool win32_init_tcp_ip()
|
||||
{
|
||||
if (win32_have_tcpip())
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD( 2, 0 );
|
||||
WORD wVersionRequested = MAKEWORD( 2, 2 );
|
||||
WSADATA wsaData;
|
||||
/* Be a good citizen: maybe another lib has already initialised
|
||||
sockets, so dont clobber them unless necessary */
|
||||
@@ -483,56 +491,117 @@ static my_bool win32_init_tcp_ip()
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
|
||||
#ifdef __NETWARE__
|
||||
/*
|
||||
Basic initialisation for netware
|
||||
*/
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
PSI_mutex_key key_my_file_info_mutex;
|
||||
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
|
||||
|
||||
static void netware_init()
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
PSI_mutex_key key_LOCK_localtime_r;
|
||||
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
|
||||
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
PSI_mutex_key key_LOCK_gethostbyname_r;
|
||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
|
||||
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
|
||||
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
|
||||
key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc,
|
||||
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
|
||||
key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time,
|
||||
key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
|
||||
|
||||
static PSI_mutex_info all_mysys_mutexes[]=
|
||||
{
|
||||
char cwd[PATH_MAX], *name;
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
{ &key_my_file_info_mutex, "st_my_file_info:mutex", 0},
|
||||
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
{ &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
|
||||
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
{ &key_LOCK_gethostbyname_r, "LOCK_gethostbyname_r", PSI_FLAG_GLOBAL},
|
||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||
{ &key_BITMAP_mutex, "BITMAP::mutex", 0},
|
||||
{ &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
|
||||
{ &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
|
||||
{ &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0},
|
||||
{ &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL},
|
||||
{ &key_my_thread_var_mutex, "my_thread_var::mutex", 0},
|
||||
{ &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_isam, "THR_LOCK_isam", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0},
|
||||
{ &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_time, "THR_LOCK_time", PSI_FLAG_GLOBAL},
|
||||
{ &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
|
||||
{ &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL}
|
||||
};
|
||||
|
||||
DBUG_ENTER("netware_init");
|
||||
PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
|
||||
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
|
||||
key_THR_COND_threads;
|
||||
|
||||
/* init only if we are not a client library */
|
||||
if (my_progname)
|
||||
{
|
||||
#if SUPPORTED_BY_LIBC /* Removed until supported in Libc */
|
||||
struct termios tp;
|
||||
/* Disable control characters */
|
||||
tcgetattr(STDIN_FILENO, &tp);
|
||||
tp.c_cc[VINTR] = _POSIX_VDISABLE;
|
||||
tp.c_cc[VEOF] = _POSIX_VDISABLE;
|
||||
tp.c_cc[VSUSP] = _POSIX_VDISABLE;
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &tp);
|
||||
#endif /* SUPPORTED_BY_LIBC */
|
||||
static PSI_cond_info all_mysys_conds[]=
|
||||
{
|
||||
{ &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL},
|
||||
{ &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0},
|
||||
{ &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0},
|
||||
{ &key_my_thread_var_suspend, "my_thread_var::suspend", 0},
|
||||
{ &key_THR_COND_threads, "THR_COND_threads", 0}
|
||||
};
|
||||
|
||||
/* With stdout redirection */
|
||||
if (!isatty(STDOUT_FILENO))
|
||||
{
|
||||
setscreenmode(SCR_AUTOCLOSE_ON_EXIT); /* auto close the screen */
|
||||
}
|
||||
else
|
||||
{
|
||||
setscreenmode(SCR_NO_MODE); /* keep the screen up */
|
||||
}
|
||||
#ifdef USE_ALARM_THREAD
|
||||
PSI_thread_key key_thread_alarm;
|
||||
|
||||
/* Parse program name and change to base format */
|
||||
name= (char*) my_progname;
|
||||
for (; *name; name++)
|
||||
{
|
||||
if (*name == '\\')
|
||||
{
|
||||
*name = '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
*name = tolower(*name);
|
||||
}
|
||||
}
|
||||
}
|
||||
static PSI_thread_info all_mysys_threads[]=
|
||||
{
|
||||
{ &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL}
|
||||
};
|
||||
#endif /* USE_ALARM_THREAD */
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
PSI_file_key key_file_proc_meminfo;
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
PSI_file_key key_file_charset, key_file_cnf;
|
||||
|
||||
static PSI_file_info all_mysys_files[]=
|
||||
{
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
{ &key_file_proc_meminfo, "proc_meminfo", 0},
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
{ &key_file_charset, "charset", 0},
|
||||
{ &key_file_cnf, "cnf", 0}
|
||||
};
|
||||
|
||||
void my_init_mysys_psi_keys()
|
||||
{
|
||||
const char* category= "mysys";
|
||||
int count;
|
||||
|
||||
if (PSI_server == NULL)
|
||||
return;
|
||||
|
||||
count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]);
|
||||
PSI_server->register_mutex(category, all_mysys_mutexes, count);
|
||||
|
||||
count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]);
|
||||
PSI_server->register_cond(category, all_mysys_conds, count);
|
||||
|
||||
#ifdef USE_ALARM_THREAD
|
||||
count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]);
|
||||
PSI_server->register_thread(category, all_mysys_threads, count);
|
||||
#endif /* USE_ALARM_THREAD */
|
||||
|
||||
count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]);
|
||||
PSI_server->register_file(category, all_mysys_files, count);
|
||||
}
|
||||
#endif /* __NETWARE__ */
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef HAVE_LARGE_PAGES
|
||||
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
static uint my_get_large_page_size_int(void);
|
||||
static uchar* my_large_malloc_int(size_t size, myf my_flags);
|
||||
static my_bool my_large_free_int(uchar* ptr);
|
||||
|
||||
/* Gets the size of large pages from the OS */
|
||||
|
||||
uint my_get_large_page_size(void)
|
||||
{
|
||||
uint size;
|
||||
DBUG_ENTER("my_get_large_page_size");
|
||||
|
||||
if (!(size = my_get_large_page_size_int()))
|
||||
fprintf(stderr, "Warning: Failed to determine large page size\n");
|
||||
|
||||
DBUG_RETURN(size);
|
||||
}
|
||||
|
||||
/*
|
||||
General large pages allocator.
|
||||
Tries to allocate memory from large pages pool and falls back to
|
||||
my_malloc_lock() in case of failure
|
||||
*/
|
||||
|
||||
uchar* my_large_malloc(size_t size, myf my_flags)
|
||||
{
|
||||
uchar* ptr;
|
||||
DBUG_ENTER("my_large_malloc");
|
||||
|
||||
if (my_use_large_pages && my_large_page_size)
|
||||
{
|
||||
if ((ptr = my_large_malloc_int(size, my_flags)) != NULL)
|
||||
DBUG_RETURN(ptr);
|
||||
if (my_flags & MY_WME)
|
||||
fprintf(stderr, "Warning: Using conventional memory pool\n");
|
||||
}
|
||||
|
||||
DBUG_RETURN(my_malloc_lock(size, my_flags));
|
||||
}
|
||||
|
||||
/*
|
||||
General large pages deallocator.
|
||||
Tries to deallocate memory as if it was from large pages pool and falls back
|
||||
to my_free_lock() in case of failure
|
||||
*/
|
||||
|
||||
void my_large_free(uchar* ptr)
|
||||
{
|
||||
DBUG_ENTER("my_large_free");
|
||||
|
||||
/*
|
||||
my_large_free_int() can only fail if ptr was not allocated with
|
||||
my_large_malloc_int(), i.e. my_malloc_lock() was used so we should free it
|
||||
with my_free_lock()
|
||||
*/
|
||||
if (!my_use_large_pages || !my_large_page_size || !my_large_free_int(ptr))
|
||||
my_free_lock(ptr);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
/* Linux-specific function to determine the size of large pages */
|
||||
|
||||
uint my_get_large_page_size_int(void)
|
||||
{
|
||||
MYSQL_FILE *f;
|
||||
uint size = 0;
|
||||
char buf[256];
|
||||
DBUG_ENTER("my_get_large_page_size_int");
|
||||
|
||||
if (!(f= mysql_file_fopen(key_file_proc_meminfo, "/proc/meminfo",
|
||||
O_RDONLY, MYF(MY_WME))))
|
||||
goto finish;
|
||||
|
||||
while (mysql_file_fgets(buf, sizeof(buf), f))
|
||||
if (sscanf(buf, "Hugepagesize: %u kB", &size))
|
||||
break;
|
||||
|
||||
mysql_file_fclose(f, MYF(MY_WME));
|
||||
|
||||
finish:
|
||||
DBUG_RETURN(size * 1024);
|
||||
}
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
|
||||
#if HAVE_DECL_SHM_HUGETLB
|
||||
/* Linux-specific large pages allocator */
|
||||
|
||||
uchar* my_large_malloc_int(size_t size, myf my_flags)
|
||||
{
|
||||
int shmid;
|
||||
uchar* ptr;
|
||||
struct shmid_ds buf;
|
||||
DBUG_ENTER("my_large_malloc_int");
|
||||
|
||||
/* Align block size to my_large_page_size */
|
||||
size= MY_ALIGN(size, (size_t) my_large_page_size);
|
||||
|
||||
shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W);
|
||||
if (shmid < 0)
|
||||
{
|
||||
if (my_flags & MY_WME)
|
||||
fprintf(stderr,
|
||||
"Warning: Failed to allocate %lu bytes from HugeTLB memory."
|
||||
" errno %d\n", (ulong) size, errno);
|
||||
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
ptr = (uchar*) shmat(shmid, NULL, 0);
|
||||
if (ptr == (uchar *) -1)
|
||||
{
|
||||
if (my_flags& MY_WME)
|
||||
fprintf(stderr, "Warning: Failed to attach shared memory segment,"
|
||||
" errno %d\n", errno);
|
||||
shmctl(shmid, IPC_RMID, &buf);
|
||||
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the shared memory segment so that it will be automatically freed
|
||||
after memory is detached or process exits
|
||||
*/
|
||||
shmctl(shmid, IPC_RMID, &buf);
|
||||
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
/* Linux-specific large pages deallocator */
|
||||
|
||||
my_bool my_large_free_int(uchar *ptr)
|
||||
{
|
||||
DBUG_ENTER("my_large_free_int");
|
||||
DBUG_RETURN(shmdt(ptr) == 0);
|
||||
}
|
||||
#endif /* HAVE_DECL_SHM_HUGETLB */
|
||||
|
||||
#endif /* HAVE_LARGE_PAGES */
|
||||
+34
-161
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,6 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* TODO: check for overun of memory for names. */
|
||||
/* Convert MSDOS-TIME to standar time_t (still needed?) */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
@@ -35,20 +34,14 @@
|
||||
# if defined(HAVE_NDIR_H)
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
# if defined(__WIN__)
|
||||
# include <dos.h>
|
||||
# if defined(_WIN32)
|
||||
# ifdef __BORLANDC__
|
||||
# include <dir.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#include <rms.h>
|
||||
#include <iodef.h>
|
||||
#include <descrip.h>
|
||||
#endif
|
||||
|
||||
#if defined(THREAD) && defined(HAVE_READDIR_R)
|
||||
#if defined(HAVE_READDIR_R)
|
||||
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
|
||||
#else
|
||||
#define READDIR(A,B,C) (!(C=readdir(A)))
|
||||
@@ -78,7 +71,7 @@ void my_dirend(MY_DIR *buffer)
|
||||
ALIGN_SIZE(sizeof(MY_DIR))));
|
||||
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
|
||||
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
|
||||
my_free((uchar*) buffer,MYF(0));
|
||||
my_free(buffer);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
} /* my_dirend */
|
||||
@@ -92,7 +85,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
|
||||
} /* comp_names */
|
||||
|
||||
|
||||
#if !defined(__WIN__)
|
||||
#if !defined(_WIN32)
|
||||
|
||||
MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
{
|
||||
@@ -104,14 +97,13 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char tmp_path[FN_REFLEN+1],*tmp_file;
|
||||
#ifdef THREAD
|
||||
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
|
||||
#endif
|
||||
|
||||
DBUG_ENTER("my_dir");
|
||||
DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
|
||||
|
||||
#if defined(THREAD) && !defined(HAVE_READDIR_R)
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
#endif
|
||||
|
||||
dirp = opendir(directory_file_name(tmp_path,(char *) path));
|
||||
@@ -132,7 +124,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
|
||||
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
|
||||
{
|
||||
my_free((uchar*) buffer,MYF(0));
|
||||
my_free(buffer);
|
||||
goto error;
|
||||
}
|
||||
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
|
||||
@@ -142,11 +134,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
|
||||
tmp_file=strend(tmp_path);
|
||||
|
||||
#ifdef THREAD
|
||||
dp= (struct dirent*) dirent_tmp;
|
||||
#else
|
||||
dp=0;
|
||||
#endif
|
||||
|
||||
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
|
||||
{
|
||||
@@ -160,8 +148,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
goto error;
|
||||
|
||||
bzero(finfo.mystat, sizeof(MY_STAT));
|
||||
VOID(strmov(tmp_file,dp->d_name));
|
||||
VOID(my_stat(tmp_path, finfo.mystat, MyFlags));
|
||||
(void) strmov(tmp_file,dp->d_name);
|
||||
(void) my_stat(tmp_path, finfo.mystat, MyFlags);
|
||||
if (!(finfo.mystat->st_mode & MY_S_IREAD))
|
||||
continue;
|
||||
}
|
||||
@@ -173,8 +161,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
}
|
||||
|
||||
(void) closedir(dirp);
|
||||
#if defined(THREAD) && !defined(HAVE_READDIR_R)
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
#endif
|
||||
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
|
||||
result->number_off_files= dir_entries_storage->elements;
|
||||
@@ -185,8 +173,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
DBUG_RETURN(result);
|
||||
|
||||
error:
|
||||
#if defined(THREAD) && !defined(HAVE_READDIR_R)
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
#if !defined(HAVE_READDIR_R)
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
#endif
|
||||
my_errno=errno;
|
||||
if (dirp)
|
||||
@@ -200,9 +188,6 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
|
||||
/*
|
||||
* Convert from directory name to filename.
|
||||
* On VMS:
|
||||
* xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
|
||||
* xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
|
||||
* On UNIX, it's simple: just make sure there is a terminating /
|
||||
|
||||
* Returns pointer to dst;
|
||||
@@ -210,11 +195,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
|
||||
char * directory_file_name (char * dst, const char *src)
|
||||
{
|
||||
#ifndef VMS
|
||||
|
||||
/* Process as Unix format: just remove test the final slash. */
|
||||
|
||||
char * end;
|
||||
char *end;
|
||||
|
||||
if (src[0] == 0)
|
||||
src= (char*) "."; /* Use empty as current */
|
||||
@@ -225,125 +207,7 @@ char * directory_file_name (char * dst, const char *src)
|
||||
end[1]='\0';
|
||||
}
|
||||
return dst;
|
||||
|
||||
#else /* VMS */
|
||||
|
||||
long slen;
|
||||
long rlen;
|
||||
char * ptr, rptr;
|
||||
char bracket;
|
||||
struct FAB fab = cc$rms_fab;
|
||||
struct NAM nam = cc$rms_nam;
|
||||
char esa[NAM$C_MAXRSS];
|
||||
|
||||
if (! src[0])
|
||||
src="[.]"; /* Empty is == current dir */
|
||||
|
||||
slen = strlen (src) - 1;
|
||||
if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
|
||||
src[slen] == FN_DEVCHAR)
|
||||
{
|
||||
/* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
|
||||
fab.fab$l_fna = src;
|
||||
fab.fab$b_fns = slen + 1;
|
||||
fab.fab$l_nam = &nam;
|
||||
fab.fab$l_fop = FAB$M_NAM;
|
||||
|
||||
nam.nam$l_esa = esa;
|
||||
nam.nam$b_ess = sizeof esa;
|
||||
nam.nam$b_nop |= NAM$M_SYNCHK;
|
||||
|
||||
/* We call SYS$PARSE to handle such things as [--] for us. */
|
||||
if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
|
||||
{
|
||||
slen = nam.nam$b_esl - 1;
|
||||
if (esa[slen] == ';' && esa[slen - 1] == '.')
|
||||
slen -= 2;
|
||||
esa[slen + 1] = '\0';
|
||||
src = esa;
|
||||
}
|
||||
if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
|
||||
{
|
||||
/* what about when we have logical_name:???? */
|
||||
if (src[slen] == FN_DEVCHAR)
|
||||
{ /* Xlate logical name and see what we get */
|
||||
VOID(strmov(dst,src));
|
||||
dst[slen] = 0; /* remove colon */
|
||||
if (!(src = getenv (dst)))
|
||||
return dst; /* Can't translate */
|
||||
|
||||
/* should we jump to the beginning of this procedure?
|
||||
Good points: allows us to use logical names that xlate
|
||||
to Unix names,
|
||||
Bad points: can be a problem if we just translated to a device
|
||||
name...
|
||||
For now, I'll punt and always expect VMS names, and hope for
|
||||
the best! */
|
||||
|
||||
slen = strlen (src) - 1;
|
||||
if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
|
||||
{ /* no recursion here! */
|
||||
VOID(strmov(dst, src));
|
||||
return(dst);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* not a directory spec */
|
||||
VOID(strmov(dst, src));
|
||||
return(dst);
|
||||
}
|
||||
}
|
||||
|
||||
bracket = src[slen]; /* End char */
|
||||
if (!(ptr = strchr (src, bracket - 2)))
|
||||
{ /* no opening bracket */
|
||||
VOID(strmov (dst, src));
|
||||
return dst;
|
||||
}
|
||||
if (!(rptr = strrchr (src, '.')))
|
||||
rptr = ptr;
|
||||
slen = rptr - src;
|
||||
VOID(strmake (dst, src, slen));
|
||||
|
||||
if (*rptr == '.')
|
||||
{ /* Put bracket and add */
|
||||
dst[slen++] = bracket; /* (rptr+1) after this */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we have the top-level of a rooted directory (i.e. xx:[000000]),
|
||||
then translate the device and recurse. */
|
||||
|
||||
if (dst[slen - 1] == ':'
|
||||
&& dst[slen - 2] != ':' /* skip decnet nodes */
|
||||
&& strcmp(src + slen, "[000000]") == 0)
|
||||
{
|
||||
dst[slen - 1] = '\0';
|
||||
if ((ptr = getenv (dst))
|
||||
&& (rlen = strlen (ptr) - 1) > 0
|
||||
&& (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
|
||||
&& ptr[rlen - 1] == '.')
|
||||
{
|
||||
VOID(strmov(esa,ptr));
|
||||
esa[rlen - 1] = FN_C_AFTER_DIR;
|
||||
esa[rlen] = '\0';
|
||||
return (directory_file_name (dst, esa));
|
||||
}
|
||||
else
|
||||
dst[slen - 1] = ':';
|
||||
}
|
||||
VOID(strmov(dst+slen,"[000000]"));
|
||||
slen += 8;
|
||||
}
|
||||
VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
|
||||
return dst;
|
||||
}
|
||||
VOID(strmov(dst, src));
|
||||
if (dst[slen] == '/' && slen > 1)
|
||||
dst[slen] = 0;
|
||||
return dst;
|
||||
#endif /* VMS */
|
||||
} /* directory_file_name */
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -401,7 +265,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
|
||||
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
|
||||
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
|
||||
{
|
||||
my_free((uchar*) buffer,MYF(0));
|
||||
my_free(buffer);
|
||||
goto error;
|
||||
}
|
||||
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
|
||||
@@ -507,19 +371,24 @@ error:
|
||||
DBUG_RETURN((MY_DIR *) NULL);
|
||||
} /* my_dir */
|
||||
|
||||
#endif /* __WIN__ */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/****************************************************************************
|
||||
** File status
|
||||
** Note that MY_STAT is assumed to be same as struct stat
|
||||
****************************************************************************/
|
||||
|
||||
int my_fstat(int Filedes, MY_STAT *stat_area,
|
||||
|
||||
int my_fstat(File Filedes, MY_STAT *stat_area,
|
||||
myf MyFlags __attribute__((unused)))
|
||||
{
|
||||
DBUG_ENTER("my_fstat");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
|
||||
#ifdef _WIN32
|
||||
DBUG_RETURN(my_win_fstat(Filedes, stat_area));
|
||||
#else
|
||||
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -531,15 +400,19 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
|
||||
(long) stat_area, my_flags));
|
||||
|
||||
if ((m_used= (stat_area == NULL)))
|
||||
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
|
||||
if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
|
||||
goto error;
|
||||
if (! stat((char *) path, (struct stat *) stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (! stat((char *) path, (struct stat *) stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
#else
|
||||
if (! my_win_stat(path, stat_area) )
|
||||
DBUG_RETURN(stat_area);
|
||||
#endif
|
||||
DBUG_PRINT("error",("Got errno: %d from stat", errno));
|
||||
my_errno= errno;
|
||||
if (m_used) /* Free if new area */
|
||||
my_free((uchar*) stat_area,MYF(0));
|
||||
my_free(stat_area);
|
||||
|
||||
error:
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright (C) 2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
This is needed to be able to compile with original libwrap header
|
||||
files that don't have the prototypes
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_libwrap.h>
|
||||
|
||||
#ifdef HAVE_LIBWRAP
|
||||
|
||||
void my_fromhost(struct request_info *req)
|
||||
{
|
||||
fromhost(req);
|
||||
}
|
||||
|
||||
int my_hosts_access(struct request_info *req)
|
||||
{
|
||||
return hosts_access(req);
|
||||
}
|
||||
|
||||
char *my_eval_client(struct request_info *req)
|
||||
{
|
||||
return eval_client(req);
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBWRAP */
|
||||
@@ -0,0 +1,223 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <errno.h>
|
||||
#undef MY_HOW_OFTEN_TO_ALARM
|
||||
#define MY_HOW_OFTEN_TO_ALARM ((int) my_time_to_wait_for_lock)
|
||||
#ifdef NO_ALARM_LOOP
|
||||
#undef NO_ALARM_LOOP
|
||||
#endif
|
||||
#include <my_alarm.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN_LOCK_INFINITE -1
|
||||
#define WIN_LOCK_SLEEP_MILLIS 100
|
||||
|
||||
static int win_lock(File fd, int locktype, my_off_t start, my_off_t length,
|
||||
int timeout_sec)
|
||||
{
|
||||
LARGE_INTEGER liOffset,liLength;
|
||||
DWORD dwFlags;
|
||||
OVERLAPPED ov= {0};
|
||||
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
|
||||
DWORD lastError= 0;
|
||||
int i;
|
||||
int timeout_millis= timeout_sec * 1000;
|
||||
|
||||
DBUG_ENTER("win_lock");
|
||||
|
||||
liOffset.QuadPart= start;
|
||||
liLength.QuadPart= length;
|
||||
|
||||
ov.Offset= liOffset.LowPart;
|
||||
ov.OffsetHigh= liOffset.HighPart;
|
||||
|
||||
if (locktype == F_UNLCK)
|
||||
{
|
||||
if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
/*
|
||||
For compatibility with fcntl implementation, ignore error,
|
||||
if region was not locked
|
||||
*/
|
||||
if (GetLastError() == ERROR_NOT_LOCKED)
|
||||
{
|
||||
SetLastError(0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
else if (locktype == F_RDLCK)
|
||||
/* read lock is mapped to a shared lock. */
|
||||
dwFlags= 0;
|
||||
else
|
||||
/* write lock is mapped to an exclusive lock. */
|
||||
dwFlags= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
|
||||
/*
|
||||
Drop old lock first to avoid double locking.
|
||||
During analyze of Bug#38133 (Myisamlog test fails on Windows)
|
||||
I met the situation that the program myisamlog locked the file
|
||||
exclusively, then additionally shared, then did one unlock, and
|
||||
then blocked on an attempt to lock it exclusively again.
|
||||
Unlocking before every lock fixed the problem.
|
||||
Note that this introduces a race condition. When the application
|
||||
wants to convert an exclusive lock into a shared one, it will now
|
||||
first unlock the file and then lock it shared. A waiting exclusive
|
||||
lock could step in here. For reasons described in Bug#38133 and
|
||||
Bug#41124 (Server hangs on Windows with --external-locking after
|
||||
INSERT...SELECT) and in the review thread at
|
||||
http://lists.mysql.com/commits/60721 it seems to be the better
|
||||
option than not to unlock here.
|
||||
If one day someone notices a way how to do file lock type changes
|
||||
on Windows without unlocking before taking the new lock, please
|
||||
change this code accordingly to fix the race condition.
|
||||
*/
|
||||
if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) &&
|
||||
(GetLastError() != ERROR_NOT_LOCKED))
|
||||
goto error;
|
||||
|
||||
if (timeout_sec == WIN_LOCK_INFINITE)
|
||||
{
|
||||
if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dwFlags|= LOCKFILE_FAIL_IMMEDIATELY;
|
||||
timeout_millis= timeout_sec * 1000;
|
||||
/* Try lock in a loop, until the lock is acquired or timeout happens */
|
||||
for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS)
|
||||
{
|
||||
if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (GetLastError() != ERROR_LOCK_VIOLATION)
|
||||
goto error;
|
||||
|
||||
if (i >= timeout_millis)
|
||||
break;
|
||||
Sleep(WIN_LOCK_SLEEP_MILLIS);
|
||||
}
|
||||
|
||||
/* timeout */
|
||||
errno= EAGAIN;
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
error:
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lock a part of a file
|
||||
|
||||
RETURN VALUE
|
||||
0 Success
|
||||
-1 An error has occured and 'my_errno' is set
|
||||
to indicate the actual error code.
|
||||
*/
|
||||
|
||||
int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
|
||||
myf MyFlags)
|
||||
{
|
||||
#ifdef HAVE_FCNTL
|
||||
int value;
|
||||
ALARM_VARIABLES;
|
||||
#endif
|
||||
|
||||
DBUG_ENTER("my_lock");
|
||||
DBUG_PRINT("my",("fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
|
||||
fd,locktype,(long) start,(long) length,MyFlags));
|
||||
if (my_disable_locking)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
int timeout_sec;
|
||||
if (MyFlags & MY_DONT_WAIT)
|
||||
timeout_sec= 0;
|
||||
else
|
||||
timeout_sec= WIN_LOCK_INFINITE;
|
||||
|
||||
if (win_lock(fd, locktype, start, length, timeout_sec) == 0)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#else
|
||||
#if defined(HAVE_FCNTL)
|
||||
{
|
||||
struct flock lock;
|
||||
|
||||
lock.l_type= (short) locktype;
|
||||
lock.l_whence= SEEK_SET;
|
||||
lock.l_start= (off_t) start;
|
||||
lock.l_len= (off_t) length;
|
||||
|
||||
if (MyFlags & MY_DONT_WAIT)
|
||||
{
|
||||
if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
|
||||
DBUG_RETURN(0); /* Ok, file locked */
|
||||
DBUG_PRINT("info",("Was locked, trying with alarm"));
|
||||
ALARM_INIT;
|
||||
while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
|
||||
errno == EINTR)
|
||||
{ /* Setup again so we don`t miss it */
|
||||
ALARM_REINIT;
|
||||
}
|
||||
ALARM_END;
|
||||
if (value != -1)
|
||||
DBUG_RETURN(0);
|
||||
if (errno == EINTR)
|
||||
errno=EAGAIN;
|
||||
}
|
||||
else if (fcntl(fd,F_SETLKW,&lock) != -1) /* Wait until a lock */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
#else
|
||||
if (MyFlags & MY_SEEK_NOT_DONE)
|
||||
{
|
||||
if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
|
||||
== MY_FILEPOS_ERROR)
|
||||
{
|
||||
/*
|
||||
If an error has occured in my_seek then we will already
|
||||
have an error code in my_errno; Just return error code.
|
||||
*/
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
if (lockf(fd,locktype,length) != -1)
|
||||
DBUG_RETURN(0);
|
||||
#endif /* HAVE_FCNTL */
|
||||
#endif /* HAVE_LOCKING */
|
||||
|
||||
/* We got an error. We don't want EACCES errors */
|
||||
my_errno=(errno == EACCES) ? EAGAIN : errno ? errno : -1;
|
||||
|
||||
if (MyFlags & MY_WME)
|
||||
{
|
||||
if (locktype == F_UNLCK)
|
||||
my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
|
||||
else
|
||||
my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
|
||||
}
|
||||
DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
|
||||
DBUG_RETURN(-1);
|
||||
} /* my_lock */
|
||||
@@ -0,0 +1,98 @@
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Alloc a block of locked memory */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_list.h>
|
||||
|
||||
#ifdef HAVE_MLOCK
|
||||
#include <sys/mman.h>
|
||||
|
||||
struct st_mem_list
|
||||
{
|
||||
LIST list;
|
||||
uchar *page;
|
||||
uint size;
|
||||
};
|
||||
|
||||
LIST *mem_list;
|
||||
|
||||
uchar *my_malloc_lock(uint size,myf MyFlags)
|
||||
{
|
||||
int success;
|
||||
uint pagesize=sysconf(_SC_PAGESIZE);
|
||||
uchar *ptr;
|
||||
struct st_mem_list *element;
|
||||
DBUG_ENTER("my_malloc_lock");
|
||||
|
||||
size=((size-1) & ~(pagesize-1))+pagesize;
|
||||
if (!(ptr=memalign(pagesize,size)))
|
||||
{
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
success = mlock((uchar*) ptr,size);
|
||||
if (success != 0 && geteuid() == 0)
|
||||
{
|
||||
DBUG_PRINT("warning",("Failed to lock memory. errno %d\n",
|
||||
errno));
|
||||
fprintf(stderr, "Warning: Failed to lock memory. errno %d\n",
|
||||
errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add block in a list for munlock */
|
||||
if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags)))
|
||||
{
|
||||
(void) munlock((uchar*) ptr,size);
|
||||
free(ptr);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
element->list.data=(uchar*) element;
|
||||
element->page=ptr;
|
||||
element->size=size;
|
||||
mysql_mutex_lock(&THR_LOCK_malloc);
|
||||
mem_list=list_add(mem_list,&element->list);
|
||||
mysql_mutex_unlock(&THR_LOCK_malloc);
|
||||
}
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
|
||||
void my_free_lock(uchar *ptr)
|
||||
{
|
||||
LIST *list;
|
||||
struct st_mem_list *element=0;
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_malloc);
|
||||
for (list=mem_list ; list ; list=list->next)
|
||||
{
|
||||
element=(struct st_mem_list*) list->data;
|
||||
if (ptr == element->page)
|
||||
{ /* Found locked mem */
|
||||
(void) munlock((uchar*) ptr,element->size);
|
||||
mem_list=list_delete(mem_list,list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_malloc);
|
||||
my_free(element);
|
||||
free(ptr); /* Free even if not locked */
|
||||
}
|
||||
|
||||
#endif /* HAVE_MLOCK */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -11,28 +11,31 @@
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
|
||||
#undef SAFEMALLOC
|
||||
#endif
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/* My memory allocator */
|
||||
/**
|
||||
Allocate a sized block of memory.
|
||||
|
||||
@param size The size of the memory block in bytes.
|
||||
@param flags Failure action modifiers (bitmasks).
|
||||
|
||||
@return A pointer to the allocated memory block, or NULL on failure.
|
||||
*/
|
||||
void *my_malloc(size_t size, myf my_flags)
|
||||
{
|
||||
void* point;
|
||||
DBUG_ENTER("my_malloc");
|
||||
DBUG_PRINT("my",("size: %lu my_flags: %d", (ulong) size, my_flags));
|
||||
|
||||
/* Safety */
|
||||
if (!size)
|
||||
size=1; /* Safety */
|
||||
size=1;
|
||||
|
||||
point= (char *) malloc(size);
|
||||
point= malloc(size);
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
free(point);
|
||||
@@ -52,33 +55,87 @@ void *my_malloc(size_t size, myf my_flags)
|
||||
exit(1);
|
||||
}
|
||||
else if (my_flags & MY_ZEROFILL)
|
||||
bzero(point,size);
|
||||
DBUG_PRINT("exit",("ptr: 0x%lx", (long) point));
|
||||
DBUG_RETURN((void*) point);
|
||||
} /* my_malloc */
|
||||
bzero(point, size);
|
||||
DBUG_PRINT("exit",("ptr: %p", point));
|
||||
DBUG_RETURN(point);
|
||||
}
|
||||
|
||||
|
||||
/* Free memory allocated with my_malloc */
|
||||
/*ARGSUSED*/
|
||||
/**
|
||||
@brief wrapper around realloc()
|
||||
|
||||
void my_no_flags_free(void* ptr)
|
||||
@param oldpoint pointer to currently allocated area
|
||||
@param size new size requested, must be >0
|
||||
@param my_flags flags
|
||||
|
||||
@note if size==0 realloc() may return NULL; my_realloc() treats this as an
|
||||
error which is not the intention of realloc()
|
||||
*/
|
||||
void *my_realloc(void *oldpoint, size_t size, myf my_flags)
|
||||
{
|
||||
void *point;
|
||||
DBUG_ENTER("my_realloc");
|
||||
DBUG_PRINT("my",("ptr: %p size: %lu my_flags: %d", oldpoint,
|
||||
(ulong) size, my_flags));
|
||||
|
||||
DBUG_ASSERT(size > 0);
|
||||
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
|
||||
DBUG_RETURN(my_malloc(size, my_flags));
|
||||
#ifdef USE_HALLOC
|
||||
if (!(point = malloc(size)))
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & MY_FAE+MY_WME)
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(point,oldpoint,size);
|
||||
free(oldpoint);
|
||||
}
|
||||
#else
|
||||
if ((point= realloc(oldpoint, size)) == NULL)
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), size);
|
||||
}
|
||||
#endif
|
||||
DBUG_PRINT("exit",("ptr: %p", point));
|
||||
DBUG_RETURN(point);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Free memory allocated with my_malloc.
|
||||
|
||||
@remark Relies on free being able to handle a NULL argument.
|
||||
|
||||
@param ptr Pointer to the memory allocated by my_malloc.
|
||||
*/
|
||||
void my_free(void *ptr)
|
||||
{
|
||||
DBUG_ENTER("my_free");
|
||||
DBUG_PRINT("my",("ptr: 0x%lx", (long) ptr));
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
DBUG_PRINT("my",("ptr: %p", ptr));
|
||||
free(ptr);
|
||||
DBUG_VOID_RETURN;
|
||||
} /* my_free */
|
||||
}
|
||||
|
||||
|
||||
/* malloc and copy */
|
||||
|
||||
void* my_memdup(const void *from, size_t length, myf my_flags)
|
||||
void *my_memdup(const void *from, size_t length, myf my_flags)
|
||||
{
|
||||
void *ptr;
|
||||
if ((ptr= my_malloc(length,my_flags)) != 0)
|
||||
memcpy(ptr, from, length);
|
||||
return(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,18 +144,19 @@ char *my_strdup(const char *from, myf my_flags)
|
||||
char *ptr;
|
||||
size_t length= strlen(from)+1;
|
||||
if ((ptr= (char*) my_malloc(length, my_flags)))
|
||||
memcpy((uchar*) ptr, (uchar*) from,(size_t) length);
|
||||
return(ptr);
|
||||
memcpy(ptr, from, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
char *my_strndup(const char *from, size_t length, myf my_flags)
|
||||
{
|
||||
char *ptr;
|
||||
if ((ptr= (char*) my_malloc(length+1,my_flags)) != 0)
|
||||
if ((ptr= (char*) my_malloc(length+1, my_flags)))
|
||||
{
|
||||
memcpy((uchar*) ptr, (uchar*) from, length);
|
||||
ptr[length]=0;
|
||||
memcpy(ptr, from, length);
|
||||
ptr[length]= 0;
|
||||
}
|
||||
return((char*) ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
my_memmem, port of a GNU extension.
|
||||
|
||||
Returns a pointer to the beginning of the substring, needle, or NULL if the
|
||||
substring is not found in haystack.
|
||||
*/
|
||||
|
||||
void *my_memmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen)
|
||||
{
|
||||
const unsigned char *cursor;
|
||||
const unsigned char *last_possible_needle_location =
|
||||
(unsigned char *)haystack + haystacklen - needlelen;
|
||||
|
||||
/* Easy answers */
|
||||
if (needlelen > haystacklen) return(NULL);
|
||||
if (needle == NULL) return(NULL);
|
||||
if (haystack == NULL) return(NULL);
|
||||
if (needlelen == 0) return(NULL);
|
||||
if (haystacklen == 0) return(NULL);
|
||||
|
||||
for (cursor = haystack; cursor <= last_possible_needle_location; cursor++) {
|
||||
if (memcmp(needle, cursor, needlelen) == 0) {
|
||||
return((void *) cursor);
|
||||
}
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef MAIN
|
||||
#include <assert.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char haystack[10], needle[3];
|
||||
|
||||
memmove(haystack, "0123456789", 10);
|
||||
|
||||
memmove(needle, "no", 2);
|
||||
assert(my_memmem(haystack, 10, needle, 2) == NULL);
|
||||
|
||||
memmove(needle, "345", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
|
||||
memmove(needle, "789", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
assert(my_memmem(haystack, 9, needle, 3) == NULL);
|
||||
|
||||
memmove(needle, "012", 3);
|
||||
assert(my_memmem(haystack, 10, needle, 3) != NULL);
|
||||
assert(my_memmem(NULL, 10, needle, 3) == NULL);
|
||||
|
||||
assert(my_memmem(NULL, 10, needle, 3) == NULL);
|
||||
assert(my_memmem(haystack, 0, needle, 3) == NULL);
|
||||
assert(my_memmem(haystack, 10, NULL, 3) == NULL);
|
||||
assert(my_memmem(haystack, 10, needle, 0) == NULL);
|
||||
|
||||
assert(my_memmem(haystack, 1, needle, 3) == NULL);
|
||||
|
||||
printf("success\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,18 +15,14 @@
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
int my_message_no_curses(uint error __attribute__((unused)),
|
||||
const char *str, myf MyFlags)
|
||||
void my_message_stderr(uint error __attribute__((unused)),
|
||||
const char *str, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_message_no_curses");
|
||||
DBUG_ENTER("my_message_stderr");
|
||||
DBUG_PRINT("enter",("message: %s",str));
|
||||
(void) fflush(stdout);
|
||||
if (MyFlags & ME_BELL)
|
||||
#ifdef __NETWARE__
|
||||
ringbell(); /* Bell */
|
||||
#else
|
||||
(void) fputc('\007',stderr); /* Bell */
|
||||
#endif /* __NETWARE__ */
|
||||
(void) fputc('\007', stderr);
|
||||
if (my_progname)
|
||||
{
|
||||
(void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
|
||||
@@ -34,5 +30,5 @@ int my_message_no_curses(uint error __attribute__((unused)),
|
||||
(void)fputs(str,stderr);
|
||||
(void)fputc('\n',stderr);
|
||||
(void)fflush(stderr);
|
||||
DBUG_RETURN(0);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __WIN__
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
int my_mkdir(const char *dir, int Flags, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_dir");
|
||||
DBUG_PRINT("enter",("dir: %s",dir));
|
||||
|
||||
#if defined(__WIN__)
|
||||
if (mkdir((char*) dir))
|
||||
#else
|
||||
if (mkdir((char*) dir, Flags & my_umask_dir))
|
||||
#endif
|
||||
{
|
||||
my_errno=errno;
|
||||
DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir));
|
||||
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
|
||||
my_error(EE_CANT_MKDIR, MYF(ME_BELL+ME_WAITTANG), dir, my_errno);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
|
||||
/*
|
||||
system msync() only syncs mmap'ed area to fs cache.
|
||||
fsync() is required to really sync to disc
|
||||
*/
|
||||
int my_msync(int fd, void *addr, size_t len, int flags)
|
||||
{
|
||||
msync(addr, len, flags);
|
||||
return my_sync(fd, MYF(0));
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
static SECURITY_ATTRIBUTES mmap_security_attributes=
|
||||
{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
|
||||
|
||||
void *my_mmap(void *addr, size_t len, int prot,
|
||||
int flags, File fd, my_off_t offset)
|
||||
{
|
||||
HANDLE hFileMap;
|
||||
LPVOID ptr;
|
||||
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
|
||||
DBUG_ENTER("my_mmap");
|
||||
DBUG_PRINT("mysys", ("map fd: %d", fd));
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
|
||||
hFileMap=CreateFileMapping(hFile, &mmap_security_attributes,
|
||||
PAGE_READWRITE, 0, (DWORD) len, NULL);
|
||||
if (hFileMap == 0)
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
|
||||
ptr=MapViewOfFile(hFileMap,
|
||||
prot & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ,
|
||||
(DWORD)(offset >> 32), (DWORD)offset, len);
|
||||
|
||||
/*
|
||||
MSDN explicitly states that it's possible to close File Mapping Object
|
||||
even when a view is not unmapped - then the object will be held open
|
||||
implicitly until unmap, as every view stores internally a handler of
|
||||
a corresponding File Mapping Object
|
||||
*/
|
||||
CloseHandle(hFileMap);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
DBUG_PRINT("mysys", ("mapped addr: %p", ptr));
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
DBUG_RETURN(MAP_FAILED);
|
||||
}
|
||||
|
||||
int my_munmap(void *addr, size_t len)
|
||||
{
|
||||
DBUG_ENTER("my_munmap");
|
||||
DBUG_PRINT("mysys", ("unmap addr: %p", addr));
|
||||
DBUG_RETURN(UnmapViewOfFile(addr) ? 0 : -1);
|
||||
}
|
||||
|
||||
int my_msync(int fd, void *addr, size_t len, int flags)
|
||||
{
|
||||
return FlushViewOfFile(addr, len) ? 0 : -1;
|
||||
}
|
||||
|
||||
#else
|
||||
#warning "no mmap!"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
This is a replacement of new/delete operators to be used when compiling
|
||||
with gcc 3.0.x to avoid including libstdc++
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef USE_MYSYS_NEW
|
||||
|
||||
void *operator new (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
}
|
||||
|
||||
void *operator new[] (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
}
|
||||
|
||||
void operator delete (void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[] (void *ptr) throw ()
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
C_MODE_START
|
||||
|
||||
int __cxa_pure_virtual()
|
||||
{
|
||||
assert(! "Aborted: pure virtual method called.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
#endif /* USE_MYSYS_NEW */
|
||||
|
||||
@@ -15,17 +15,14 @@
|
||||
|
||||
/* Not MT-SAFE */
|
||||
|
||||
#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
|
||||
#undef SAFEMALLOC
|
||||
#endif
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
#include <m_string.h>
|
||||
|
||||
/*
|
||||
Alloc for things we don't nead to free
|
||||
Alloc for things we don't nend to free run-time (that only
|
||||
should be free'd on exit)
|
||||
|
||||
SYNOPSIS
|
||||
my_once_alloc()
|
||||
@@ -100,7 +97,7 @@ void *my_once_memdup(const void *src, size_t len, myf myflags)
|
||||
|
||||
|
||||
/*
|
||||
Deallocate everything used by my_once_alloc
|
||||
Deallocate everything that was allocated with my_once_alloc
|
||||
|
||||
SYNOPSIS
|
||||
my_once_free()
|
||||
|
||||
+21
-221
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,9 +17,7 @@
|
||||
#include "mysys_err.h"
|
||||
#include <my_dir.h>
|
||||
#include <errno.h>
|
||||
#if defined(__WIN__)
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Open a file
|
||||
@@ -43,29 +41,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
|
||||
DBUG_ENTER("my_open");
|
||||
DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
|
||||
FileName, Flags, MyFlags));
|
||||
#if defined(__WIN__)
|
||||
/*
|
||||
Check that we don't try to open or create a file name that may
|
||||
cause problems for us in the future (like PRN)
|
||||
*/
|
||||
if (check_if_legal_filename(FileName))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN,
|
||||
EE_FILENOTFOUND, MyFlags));
|
||||
}
|
||||
#ifndef __WIN__
|
||||
if (Flags & O_SHARE)
|
||||
fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
else
|
||||
fd = open((char *) FileName, Flags | O_BINARY,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
#else
|
||||
fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
|
||||
MY_S_IREAD | MY_S_IWRITE);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
fd= my_win_open(FileName, Flags);
|
||||
#elif !defined(NO_OPEN_3)
|
||||
fd = open(FileName, Flags, my_umask); /* Normal unix */
|
||||
#else
|
||||
@@ -93,12 +70,15 @@ int my_close(File fd, myf MyFlags)
|
||||
DBUG_ENTER("my_close");
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
#ifndef _WIN32
|
||||
do
|
||||
{
|
||||
err= close(fd);
|
||||
} while (err == -1 && errno == EINTR);
|
||||
|
||||
#else
|
||||
err= my_win_close(fd);
|
||||
#endif
|
||||
if (err)
|
||||
{
|
||||
DBUG_PRINT("error",("Got error %d on close",err));
|
||||
@@ -108,14 +88,14 @@ int my_close(File fd, myf MyFlags)
|
||||
}
|
||||
if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
|
||||
{
|
||||
my_free(my_file_info[fd].name, MYF(0));
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
pthread_mutex_destroy(&my_file_info[fd].mutex);
|
||||
my_free(my_file_info[fd].name);
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
mysql_mutex_destroy(&my_file_info[fd].mutex);
|
||||
#endif
|
||||
my_file_info[fd].type = UNOPEN;
|
||||
}
|
||||
my_file_opened--;
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_RETURN(err);
|
||||
} /* my_close */
|
||||
|
||||
@@ -141,11 +121,11 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
type_of_file, uint error_message_number, myf MyFlags)
|
||||
{
|
||||
DBUG_ENTER("my_register_filename");
|
||||
if ((int) fd >= 0)
|
||||
if ((int) fd >= MY_FILE_MIN)
|
||||
{
|
||||
if ((uint) fd >= my_file_limit)
|
||||
{
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
#if !defined(HAVE_PREAD)
|
||||
my_errno= EMFILE;
|
||||
#else
|
||||
thread_safe_increment(my_file_opened,&THR_LOCK_open);
|
||||
@@ -154,20 +134,21 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&THR_LOCK_open);
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
|
||||
{
|
||||
my_file_opened++;
|
||||
my_file_total_opened++;
|
||||
my_file_info[fd].type = type_of_file;
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex,
|
||||
MY_MUTEX_INIT_FAST);
|
||||
#endif
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
DBUG_PRINT("exit",("fd: %d",fd));
|
||||
DBUG_RETURN(fd);
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_open);
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
my_errno= ENOMEM;
|
||||
}
|
||||
(void) my_close(fd, MyFlags);
|
||||
@@ -187,188 +168,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
extern void __cdecl _dosmaperr(unsigned long);
|
||||
|
||||
/*
|
||||
Open a file with sharing. Similar to _sopen() from libc, but allows managing
|
||||
share delete on win32
|
||||
|
||||
SYNOPSIS
|
||||
my_sopen()
|
||||
path fully qualified file name
|
||||
oflag operation flags
|
||||
shflag share flag
|
||||
pmode permission flags
|
||||
|
||||
RETURN VALUE
|
||||
File descriptor of opened file if success
|
||||
-1 and sets errno if fails.
|
||||
*/
|
||||
|
||||
File my_sopen(const char *path, int oflag, int shflag, int pmode)
|
||||
{
|
||||
int fh; /* handle of opened file */
|
||||
int mask;
|
||||
HANDLE osfh; /* OS handle of opened file */
|
||||
DWORD fileaccess; /* OS file access (requested) */
|
||||
DWORD fileshare; /* OS file sharing mode */
|
||||
DWORD filecreate; /* OS method of opening/creating */
|
||||
DWORD fileattrib; /* OS file attribute flags */
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
SecurityAttributes.nLength= sizeof(SecurityAttributes);
|
||||
SecurityAttributes.lpSecurityDescriptor= NULL;
|
||||
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
|
||||
|
||||
/*
|
||||
* decode the access flags
|
||||
*/
|
||||
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY: /* read access */
|
||||
fileaccess= GENERIC_READ;
|
||||
break;
|
||||
case _O_WRONLY: /* write access */
|
||||
fileaccess= GENERIC_WRITE;
|
||||
break;
|
||||
case _O_RDWR: /* read and write access */
|
||||
fileaccess= GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default: /* error, bad oflag */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L; /* not an OS error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode sharing flags
|
||||
*/
|
||||
switch (shflag) {
|
||||
case _SH_DENYRW: /* exclusive access except delete */
|
||||
fileshare= FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYWR: /* share read and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRD: /* share write and delete access */
|
||||
fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYNO: /* share read, write and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRWD: /* exclusive access */
|
||||
fileshare= 0L;
|
||||
break;
|
||||
case _SH_DENYWRD: /* share read access */
|
||||
fileshare= FILE_SHARE_READ;
|
||||
break;
|
||||
case _SH_DENYRDD: /* share write access */
|
||||
fileshare= FILE_SHARE_WRITE;
|
||||
break;
|
||||
case _SH_DENYDEL: /* share read and write access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
default: /* error, bad shflag */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L; /* not an OS error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode open/create method flags
|
||||
*/
|
||||
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
|
||||
case 0:
|
||||
case _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= OPEN_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT:
|
||||
filecreate= OPEN_ALWAYS;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_EXCL:
|
||||
case _O_CREAT | _O_TRUNC | _O_EXCL:
|
||||
filecreate= CREATE_NEW;
|
||||
break;
|
||||
|
||||
case _O_TRUNC:
|
||||
case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= TRUNCATE_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_TRUNC:
|
||||
filecreate= CREATE_ALWAYS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this can't happen ... all cases are covered */
|
||||
errno= EINVAL;
|
||||
_doserrno= 0L;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode file attribute flags if _O_CREAT was specified
|
||||
*/
|
||||
fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
|
||||
if (oflag & _O_CREAT)
|
||||
{
|
||||
_umask((mask= _umask(0)));
|
||||
|
||||
if (!((pmode & ~mask) & _S_IWRITE))
|
||||
fileattrib= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set temporary file (delete-on-close) attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_TEMPORARY)
|
||||
{
|
||||
fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
fileaccess|= DELETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set temporary file (delay-flush-to-disk) attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_SHORT_LIVED)
|
||||
fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
|
||||
|
||||
/*
|
||||
* Set sequential or random access attribute if requested.
|
||||
*/
|
||||
if (oflag & _O_SEQUENTIAL)
|
||||
fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
else if (oflag & _O_RANDOM)
|
||||
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
|
||||
|
||||
/*
|
||||
* try to open/create the file
|
||||
*/
|
||||
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
|
||||
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/*
|
||||
* OS call to open/create file failed! map the error, release
|
||||
* the lock, and return -1. note that it's not necessary to
|
||||
* call _free_osfhnd (it hasn't been used yet).
|
||||
*/
|
||||
_dosmaperr(GetLastError()); /* map error */
|
||||
return -1; /* return error to caller */
|
||||
}
|
||||
|
||||
if ((fh= _open_osfhandle((intptr_t)osfh,
|
||||
oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
|
||||
{
|
||||
_dosmaperr(GetLastError()); /* map error */
|
||||
CloseHandle(osfh);
|
||||
}
|
||||
|
||||
return fh; /* return handle */
|
||||
}
|
||||
#endif /* __WIN__ */
|
||||
|
||||
|
||||
#ifdef EXTRA_DEBUG
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2002 MySQL AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; version 2
|
||||
of the License.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
|
||||
/*
|
||||
Small functions to make code portable
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
#ifdef _AIX
|
||||
|
||||
/*
|
||||
On AIX, at least with gcc 3.1, the expression
|
||||
'(double) (ulonglong) var' doesn't always work for big unsigned
|
||||
integers like '18446744073709551615'. The end result is that the
|
||||
high bit is simply dropped. (probably bug in gcc optimizations)
|
||||
Handling the conversion in a sub function seems to work.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
double my_ulonglong2double(unsigned long long nr)
|
||||
{
|
||||
return (double) nr;
|
||||
}
|
||||
#endif /* _AIX */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -15,11 +15,15 @@
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include "my_base.h"
|
||||
#include <m_string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_PREAD
|
||||
#if defined (HAVE_PREAD) && !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Read a chunk of bytes from a file from a given position
|
||||
|
||||
@@ -46,52 +50,64 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
{
|
||||
size_t readbytes;
|
||||
int error= 0;
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
int save_errno;
|
||||
#endif
|
||||
DBUG_ENTER("my_pread");
|
||||
DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
|
||||
Filedes, (ulong) offset, (long) Buffer, (uint) Count,
|
||||
MyFlags));
|
||||
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags));
|
||||
for (;;)
|
||||
{
|
||||
#ifndef __WIN__
|
||||
errno=0; /* Linux doesn't reset this */
|
||||
#endif
|
||||
#ifndef HAVE_PREAD
|
||||
pthread_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
mysql_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
readbytes= (uint) -1;
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
|
||||
(readbytes= read(Filedes, Buffer, (uint) Count)) != Count);
|
||||
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
(readbytes= read(Filedes, Buffer, Count)) != Count);
|
||||
save_errno= errno;
|
||||
mysql_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
if (error)
|
||||
errno= save_errno;
|
||||
#else
|
||||
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
|
||||
my_errno= errno ? errno : -1;
|
||||
#if defined(_WIN32)
|
||||
readbytes= my_win_pread(Filedes, Buffer, Count, offset);
|
||||
#else
|
||||
readbytes= pread(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
if (error || readbytes != Count)
|
||||
error= (readbytes != Count);
|
||||
#endif
|
||||
if(error)
|
||||
{
|
||||
my_errno= errno ? errno : -1;
|
||||
if (errno == 0 || (readbytes != (size_t) -1 &&
|
||||
(MyFlags & (MY_NABP | MY_FNABP))))
|
||||
my_errno= HA_ERR_FILE_TOO_SHORT;
|
||||
|
||||
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
|
||||
(int) readbytes, (uint) Count,Filedes,my_errno));
|
||||
#ifdef THREAD
|
||||
|
||||
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d",
|
||||
(int) readbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
if (readbytes == (size_t) -1)
|
||||
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
else if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Read went ok; Return 0 */
|
||||
DBUG_RETURN(readbytes); /* purecov: inspected */
|
||||
DBUG_RETURN(0); /* Read went ok; Return 0 */
|
||||
DBUG_RETURN(readbytes); /* purecov: inspected */
|
||||
}
|
||||
} /* my_pread */
|
||||
|
||||
@@ -117,47 +133,50 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
|
||||
# Number of bytes read
|
||||
*/
|
||||
|
||||
size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count,
|
||||
my_off_t offset, myf MyFlags)
|
||||
{
|
||||
size_t writenbytes, written;
|
||||
size_t writtenbytes, written;
|
||||
uint errors;
|
||||
|
||||
DBUG_ENTER("my_pwrite");
|
||||
DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
|
||||
Filedes, (ulong) offset, (long) Buffer, (uint) Count,
|
||||
MyFlags));
|
||||
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, offset, Buffer, (ulong)Count, MyFlags));
|
||||
errors= 0;
|
||||
written= 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
#ifndef HAVE_PREAD
|
||||
#if !defined (HAVE_PREAD) && !defined (_WIN32)
|
||||
int error;
|
||||
writenbytes= (size_t) -1;
|
||||
pthread_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
writtenbytes= (size_t) -1;
|
||||
mysql_mutex_lock(&my_file_info[Filedes].mutex);
|
||||
error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
|
||||
(writenbytes = write(Filedes, Buffer, (uint) Count)) == Count);
|
||||
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
(writtenbytes= write(Filedes, Buffer, Count)) == Count);
|
||||
mysql_mutex_unlock(&my_file_info[Filedes].mutex);
|
||||
if (error)
|
||||
break;
|
||||
#elif defined (_WIN32)
|
||||
writtenbytes= my_win_pwrite(Filedes, Buffer, Count, offset);
|
||||
#else
|
||||
if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count)
|
||||
writtenbytes= pwrite(Filedes, Buffer, Count, offset);
|
||||
#endif
|
||||
if(writtenbytes == Count)
|
||||
break;
|
||||
my_errno= errno;
|
||||
#endif
|
||||
if (writenbytes != (size_t) -1)
|
||||
{ /* Safegueard */
|
||||
written+=writenbytes;
|
||||
Buffer+=writenbytes;
|
||||
Count-=writenbytes;
|
||||
offset+=writenbytes;
|
||||
if (writtenbytes != (size_t) -1)
|
||||
{
|
||||
written+= writtenbytes;
|
||||
Buffer+= writtenbytes;
|
||||
Count-= writtenbytes;
|
||||
offset+= writtenbytes;
|
||||
}
|
||||
DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes));
|
||||
DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
|
||||
#ifndef NO_BACKGROUND
|
||||
#ifdef THREAD
|
||||
|
||||
if (my_thread_var->abort)
|
||||
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
|
||||
#endif
|
||||
|
||||
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
|
||||
(MyFlags & MY_WAIT_IF_FULL))
|
||||
{
|
||||
@@ -165,15 +184,15 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
|
||||
if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR)
|
||||
continue; /* Retry */
|
||||
#endif
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
{
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
|
||||
my_filename(Filedes),my_errno);
|
||||
}
|
||||
DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
|
||||
}
|
||||
@@ -183,5 +202,5 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
|
||||
DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0)););
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Want only errors */
|
||||
DBUG_RETURN(writenbytes+written); /* purecov: inspected */
|
||||
DBUG_RETURN(writtenbytes+written); /* purecov: inspected */
|
||||
} /* my_pwrite */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -18,7 +18,6 @@
|
||||
#define DONT_REMAP_PTHREAD_FUNCTIONS
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#ifdef THREAD
|
||||
#include <signal.h>
|
||||
#include <m_string.h>
|
||||
#include <thr_alarm.h>
|
||||
@@ -31,46 +30,6 @@
|
||||
|
||||
uint thd_lib_detected= 0;
|
||||
|
||||
#ifndef my_pthread_setprio
|
||||
void my_pthread_setprio(pthread_t thread_id,int prior)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
||||
struct sched_param tmp_sched_param;
|
||||
bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
|
||||
tmp_sched_param.sched_priority=prior;
|
||||
VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef my_pthread_getprio
|
||||
int my_pthread_getprio(pthread_t thread_id)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
||||
struct sched_param tmp_sched_param;
|
||||
int policy;
|
||||
if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
|
||||
{
|
||||
return tmp_sched_param.sched_priority;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef my_pthread_attr_setprio
|
||||
void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_SETSCHEDPARAM
|
||||
struct sched_param tmp_sched_param;
|
||||
bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
|
||||
tmp_sched_param.sched_priority=priority;
|
||||
VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* To allow use of pthread_getspecific with two arguments */
|
||||
|
||||
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
|
||||
@@ -85,34 +44,6 @@ void *my_pthread_getspecific_imp(pthread_key_t key)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NETWARE__
|
||||
/*
|
||||
Don't kill the LibC Reaper thread or the main thread
|
||||
*/
|
||||
#include <nks/thread.h>
|
||||
#undef pthread_exit
|
||||
void my_pthread_exit(void *status)
|
||||
{
|
||||
NXThreadId_t tid;
|
||||
NXContext_t ctx;
|
||||
char name[NX_MAX_OBJECT_NAME_LEN+1] = "";
|
||||
|
||||
tid= NXThreadGetId();
|
||||
if (tid == NX_INVALID_THREAD_ID || !tid)
|
||||
return;
|
||||
if (NXThreadGetContext(tid, &ctx) ||
|
||||
NXContextGetName(ctx, name, sizeof(name)-1))
|
||||
return;
|
||||
|
||||
/*
|
||||
"MYSQLD.NLM's LibC Reaper" or "MYSQLD.NLM's main thread"
|
||||
with a debug build of LibC the reaper can have different names
|
||||
*/
|
||||
if (!strindex(name, "\'s"))
|
||||
pthread_exit(status);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
|
||||
(and DEC OSF/1 3.2 too)
|
||||
@@ -136,7 +67,7 @@ int my_sigwait(const sigset_t *set,int *sig)
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
|
||||
extern pthread_mutex_t LOCK_localtime_r;
|
||||
extern mysql_mutex_t LOCK_localtime_r;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -144,10 +75,10 @@ extern pthread_mutex_t LOCK_localtime_r;
|
||||
struct tm *localtime_r(const time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tmp;
|
||||
pthread_mutex_lock(&LOCK_localtime_r);
|
||||
mysql_mutex_lock(&LOCK_localtime_r);
|
||||
tmp=localtime(clock);
|
||||
*res= *tmp;
|
||||
pthread_mutex_unlock(&LOCK_localtime_r);
|
||||
mysql_mutex_unlock(&LOCK_localtime_r);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
@@ -161,10 +92,10 @@ struct tm *localtime_r(const time_t *clock, struct tm *res)
|
||||
struct tm *gmtime_r(const time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tmp;
|
||||
pthread_mutex_lock(&LOCK_localtime_r);
|
||||
mysql_mutex_lock(&LOCK_localtime_r);
|
||||
tmp= gmtime(clock);
|
||||
*res= *tmp;
|
||||
pthread_mutex_unlock(&LOCK_localtime_r);
|
||||
mysql_mutex_unlock(&LOCK_localtime_r);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
@@ -206,7 +137,7 @@ void sigwait_setup(sigset_t *set)
|
||||
|
||||
sact.sa_flags = 0;
|
||||
sact.sa_handler = px_handle_sig;
|
||||
memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
|
||||
memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
|
||||
sigemptyset(&unblock_mask);
|
||||
pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
|
||||
|
||||
@@ -232,7 +163,7 @@ void sigwait_setup(sigset_t *set)
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy_fixed(&sigwait_set,set,sizeof(*set));
|
||||
memcpy(&sigwait_set, set, sizeof(*set));
|
||||
pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
|
||||
pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
|
||||
}
|
||||
@@ -308,7 +239,7 @@ void sigwait_handle_sig(int sig)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_sigwait);
|
||||
sigaddset(&pending_set, sig);
|
||||
VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
|
||||
pthread_cond_signal(&COND_sigwait); /* inform sigwait() about signal */
|
||||
pthread_mutex_unlock(&LOCK_sigwait);
|
||||
}
|
||||
|
||||
@@ -320,7 +251,7 @@ void *sigwait_thread(void *set_arg)
|
||||
struct sigaction sact;
|
||||
sact.sa_flags = 0;
|
||||
sact.sa_handler = sigwait_handle_sig;
|
||||
memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
|
||||
memcpy(&sact.sa_mask, set, sizeof(*set)); /* handler isn't thread_safe */
|
||||
sigemptyset(&pending_set);
|
||||
|
||||
for (i = 1; i <= sizeof(pending_set)*8; i++)
|
||||
@@ -357,16 +288,15 @@ int sigwait(sigset_t *setp, int *sigp)
|
||||
pthread_t sigwait_thread_id;
|
||||
inited=1;
|
||||
sigemptyset(&pending_set);
|
||||
pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&COND_sigwait,NULL);
|
||||
pthread_mutex_init(&LOCK_sigwait, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&COND_sigwait, NULL);
|
||||
|
||||
pthread_attr_init(&thr_attr);
|
||||
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
|
||||
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setstacksize(&thr_attr,8196);
|
||||
my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
|
||||
VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
|
||||
VOID(pthread_attr_destroy(&thr_attr));
|
||||
pthread_create(&sigwait_thread_id, &thr_attr, sigwait_thread, setp);
|
||||
pthread_attr_destroy(&thr_attr);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&LOCK_sigwait);
|
||||
@@ -392,7 +322,7 @@ int sigwait(sigset_t *setp, int *sigp)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
|
||||
pthread_cond_wait(&COND_sigwait, &LOCK_sigwait);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -533,13 +463,7 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
|
||||
/* Some help functions */
|
||||
|
||||
int pthread_no_free(void *not_used __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_dummy(int ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif /* THREAD */
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Quicker interface to read & write. Used with my_nosys.h */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "my_nosys.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
extern size_t my_win_read(File Filedes,uchar *Buffer,size_t Count);
|
||||
#endif
|
||||
|
||||
size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
|
||||
{
|
||||
size_t readbytes;
|
||||
#ifdef _WIN32
|
||||
readbytes= my_win_read(Filedes, Buffer, Count);
|
||||
#else
|
||||
readbytes= read(Filedes, Buffer, Count);
|
||||
#endif
|
||||
if(readbytes != Count)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d"
|
||||
". This function does not retry the read!",
|
||||
(int) readbytes));
|
||||
}
|
||||
#endif
|
||||
my_errno=errno;
|
||||
return readbytes;
|
||||
}
|
||||
return (MyFlags & (MY_NABP | MY_FNABP)) ? 0 : readbytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t my_quick_write(File Filedes, const uchar *Buffer, size_t Count)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return my_win_write(Filedes, Buffer, Count);
|
||||
#else
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
size_t writtenbytes;
|
||||
#endif
|
||||
|
||||
if ((
|
||||
#ifndef DBUG_OFF
|
||||
writtenbytes =
|
||||
#endif
|
||||
(size_t) write(Filedes,Buffer,Count)) != Count)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d"
|
||||
". This function does not retry the write!",
|
||||
(int) writtenbytes));
|
||||
}
|
||||
#endif
|
||||
my_errno=errno;
|
||||
return (size_t) -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,962 @@
|
||||
/* Copyright (C) 2008-2010 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
rdtsc3 -- multi-platform timer code
|
||||
pgulutzan@mysql.com, 2005-08-29
|
||||
modified 2008-11-02
|
||||
|
||||
Functions:
|
||||
|
||||
my_timer_cycles ulonglong cycles
|
||||
my_timer_nanoseconds ulonglong nanoseconds
|
||||
my_timer_microseconds ulonglong "microseconds"
|
||||
my_timer_milliseconds ulonglong milliseconds
|
||||
my_timer_ticks ulonglong ticks
|
||||
my_timer_init initialization / test
|
||||
|
||||
We'll call the first 5 functions (the ones that return
|
||||
a ulonglong) "my_timer_xxx" functions.
|
||||
Each my_timer_xxx function returns a 64-bit timing value
|
||||
since an arbitrary 'epoch' start. Since the only purpose
|
||||
is to determine elapsed times, wall-clock time-of-day
|
||||
is not known and not relevant.
|
||||
|
||||
The my_timer_init function is necessary for initializing.
|
||||
It returns information (underlying routine name,
|
||||
frequency, resolution, overhead) about all my_timer_xxx
|
||||
functions. A program should call my_timer_init once,
|
||||
use the information to decide what my_timer_xxx function
|
||||
to use, and subsequently call that function by function
|
||||
pointer.
|
||||
|
||||
A typical use would be:
|
||||
my_timer_init() ... once, at program start
|
||||
...
|
||||
time1= my_timer_xxx() ... time before start
|
||||
[code that's timed]
|
||||
time2= my_timer_xxx() ... time after end
|
||||
elapsed_time= (time2 - time1) - overhead
|
||||
*/
|
||||
|
||||
#include "my_global.h"
|
||||
#include "my_rdtsc.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <stdio.h>
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#include <time.h> /* for clock_gettime */
|
||||
#else
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#elif defined(HAVE_TIME_H)
|
||||
#include <time.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
#include <asm/msr.h> /* for rdtscll */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
#include <sys/timeb.h> /* for ftime */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
#include <sys/times.h> /* for times */
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
#include <ia64intrin.h> /* for __GetReg */
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SUNPRO_CC) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
extern "C" ulonglong my_timer_cycles_il_sparc64();
|
||||
#elif defined(__SUNPRO_CC) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
extern "C" ulonglong my_timer_cycles_il_sparc32();
|
||||
#elif defined(__SUNPRO_CC) && defined(__i386) && defined(_ILP32)
|
||||
extern "C" ulonglong my_timer_cycles_il_i386();
|
||||
#elif defined(__SUNPRO_CC) && defined(__x86_64) && defined(_LP64)
|
||||
extern "C" ulonglong my_timer_cycles_il_x86_64();
|
||||
#elif defined(__SUNPRO_C) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
ulonglong my_timer_cycles_il_sparc64();
|
||||
#elif defined(__SUNPRO_C) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
ulonglong my_timer_cycles_il_sparc32();
|
||||
#elif defined(__SUNPRO_C) && defined(__i386) && defined(_ILP32)
|
||||
ulonglong my_timer_cycles_il_i386();
|
||||
#elif defined(__SUNPRO_C) && defined(__x86_64) && defined(_LP64)
|
||||
ulonglong my_timer_cycles_il_x86_64();
|
||||
#endif
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
/*
|
||||
icc warning #1011 is:
|
||||
missing return statement at end of non-void function
|
||||
*/
|
||||
#pragma warning (disable:1011)
|
||||
#endif
|
||||
|
||||
/*
|
||||
For cycles, we depend on RDTSC for x86 platforms,
|
||||
or on time buffer (which is not really a cycle count
|
||||
but a separate counter with less than nanosecond
|
||||
resolution) for most PowerPC platforms, or on
|
||||
gethrtime which is okay for hpux and solaris, or on
|
||||
clock_gettime(CLOCK_SGI_CYCLE) for Irix platforms,
|
||||
or on read_real_time for aix platforms. There is
|
||||
nothing for Alpha platforms, they would be tricky.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_cycles(void)
|
||||
{
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
/* This works much better if compiled with "gcc -O3". */
|
||||
ulonglong result;
|
||||
__asm__ __volatile__ ("rdtsc" : "=A" (result));
|
||||
return result;
|
||||
#elif defined(__SUNPRO_C) && defined(__i386)
|
||||
__asm("rdtsc");
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
ulonglong result;
|
||||
__asm__ __volatile__ ("rdtsc\n\t" \
|
||||
"shlq $32,%%rdx\n\t" \
|
||||
"orq %%rdx,%%rax"
|
||||
: "=a" (result) :: "%edx");
|
||||
return result;
|
||||
#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
{
|
||||
ulonglong result;
|
||||
rdtscll(result);
|
||||
return result;
|
||||
}
|
||||
#elif defined(_WIN32) && defined(_M_IX86)
|
||||
__asm {rdtsc};
|
||||
#elif defined(_WIN64) && defined(_M_X64)
|
||||
/* For 64-bit Windows: unsigned __int64 __rdtsc(); */
|
||||
return __rdtsc();
|
||||
#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */
|
||||
#elif defined(__GNUC__) && defined(__ia64__)
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("mov %0=ar.itc" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64))
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("mftb %0" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64))
|
||||
{
|
||||
/*
|
||||
mftbu means "move from time-buffer-upper to result".
|
||||
The loop is saying: x1=upper, x2=lower, x3=upper,
|
||||
if x1!=x3 there was an overflow so repeat.
|
||||
*/
|
||||
unsigned int x1, x2, x3;
|
||||
ulonglong result;
|
||||
for (;;)
|
||||
{
|
||||
__asm __volatile__ ( "mftbu %0" : "=r"(x1) );
|
||||
__asm __volatile__ ( "mftb %0" : "=r"(x2) );
|
||||
__asm __volatile__ ( "mftbu %0" : "=r"(x3) );
|
||||
if (x1 == x3) break;
|
||||
}
|
||||
result = x1;
|
||||
return ( result << 32 ) | x2;
|
||||
}
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
return (my_timer_cycles_il_sparc64());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
return (my_timer_cycles_il_sparc32());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32)
|
||||
/* This is probably redundant for __SUNPRO_C. */
|
||||
return (my_timer_cycles_il_i386());
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64)
|
||||
return (my_timer_cycles_il_x86_64());
|
||||
#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2)
|
||||
{
|
||||
ulonglong result;
|
||||
__asm __volatile__ ("rd %%tick,%0" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2)
|
||||
{
|
||||
union {
|
||||
ulonglong wholeresult;
|
||||
struct {
|
||||
ulong high;
|
||||
ulong low;
|
||||
} splitresult;
|
||||
} result;
|
||||
__asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low));
|
||||
return result.wholeresult;
|
||||
}
|
||||
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_SGI_CYCLE, &tp);
|
||||
return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec;
|
||||
}
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
/* gethrtime may appear as either cycle or nanosecond counter */
|
||||
return (ulonglong) gethrtime();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
/* re-enable warning#1011 which was only for my_timer_cycles() */
|
||||
/* There may be an icc bug which means we must leave disabled. */
|
||||
#pragma warning (default:1011)
|
||||
#endif
|
||||
|
||||
/*
|
||||
For nanoseconds, most platforms have nothing available that
|
||||
(a) doesn't require bringing in a 40-kb librt.so library
|
||||
(b) really has nanosecond resolution.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_nanoseconds(void)
|
||||
{
|
||||
#if defined(HAVE_READ_REAL_TIME)
|
||||
{
|
||||
timebasestruct_t tr;
|
||||
read_real_time(&tr, TIMEBASE_SZ);
|
||||
return (ulonglong) tr.tb_high * 1000000000 + (ulonglong) tr.tb_low;
|
||||
}
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
/* SunOS 5.10+, Solaris, HP-UX: hrtime_t gethrtime(void) */
|
||||
return (ulonglong) gethrtime();
|
||||
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec;
|
||||
}
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
{
|
||||
ulonglong tm;
|
||||
static mach_timebase_info_data_t timebase_info= {0,0};
|
||||
if (timebase_info.denom == 0)
|
||||
(void) mach_timebase_info(&timebase_info);
|
||||
tm= mach_absolute_time();
|
||||
return (tm * timebase_info.numer) / timebase_info.denom;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For microseconds, gettimeofday() is available on
|
||||
almost all platforms. On Windows we use
|
||||
QueryPerformanceCounter which will usually tick over
|
||||
3.5 million times per second, and we don't throw
|
||||
away the extra precision. (On Windows Server 2003
|
||||
the frequency is same as the cycle frequency.)
|
||||
*/
|
||||
|
||||
ulonglong my_timer_microseconds(void)
|
||||
{
|
||||
#if defined(HAVE_GETTIMEOFDAY)
|
||||
{
|
||||
static ulonglong last_value= 0;
|
||||
struct timeval tv;
|
||||
if (gettimeofday(&tv, NULL) == 0)
|
||||
last_value= (ulonglong) tv.tv_sec * 1000000 + (ulonglong) tv.tv_usec;
|
||||
else
|
||||
{
|
||||
/*
|
||||
There are reports that gettimeofday(2) can have intermittent failures
|
||||
on some platform, see for example Bug#36819.
|
||||
We are not trying again or looping, just returning the best value possible
|
||||
under the circumstances ...
|
||||
*/
|
||||
last_value++;
|
||||
}
|
||||
return last_value;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
/* QueryPerformanceCounter usually works with about 1/3 microsecond. */
|
||||
LARGE_INTEGER t_cnt;
|
||||
|
||||
QueryPerformanceCounter(&t_cnt);
|
||||
return (ulonglong) t_cnt.QuadPart;
|
||||
}
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For milliseconds, we use ftime() if it's supported
|
||||
or time()*1000 if it's not. With modern versions of
|
||||
Windows and with HP Itanium, resolution is 10-15
|
||||
milliseconds.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_milliseconds(void)
|
||||
{
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
/* ftime() is obsolete but maybe the platform is old */
|
||||
struct timeb ft;
|
||||
ftime(&ft);
|
||||
return (ulonglong)ft.time * 1000 + (ulonglong)ft.millitm;
|
||||
#elif defined(HAVE_TIME)
|
||||
return (ulonglong) time(NULL) * 1000;
|
||||
#elif defined(_WIN32)
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime( &ft );
|
||||
return ((ulonglong)ft.dwLowDateTime +
|
||||
(((ulonglong)ft.dwHighDateTime) << 32))/10000;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
For ticks, which we handle with times(), the frequency
|
||||
is usually 100/second and the overhead is surprisingly
|
||||
bad, sometimes even worse than gettimeofday's overhead.
|
||||
*/
|
||||
|
||||
ulonglong my_timer_ticks(void)
|
||||
{
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
{
|
||||
struct tms times_buf;
|
||||
return (ulonglong) times(×_buf);
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
return (ulonglong) GetTickCount();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
The my_timer_init() function and its sub-functions
|
||||
have several loops which call timers. If there's
|
||||
something wrong with a timer -- which has never
|
||||
happened in tests -- we want the loop to end after
|
||||
an arbitrary number of iterations, and my_timer_info
|
||||
will show a discouraging result. The arbitrary
|
||||
number is 1,000,000.
|
||||
*/
|
||||
#define MY_TIMER_ITERATIONS 1000000
|
||||
|
||||
/*
|
||||
Calculate overhead. Called from my_timer_init().
|
||||
Usually best_timer_overhead = cycles.overhead or
|
||||
nanoseconds.overhead, so returned amount is in
|
||||
cycles or nanoseconds. We repeat the calculation
|
||||
ten times, so that we can disregard effects of
|
||||
caching or interrupts. Result is quite consistent
|
||||
for cycles, at least. But remember it's a minimum.
|
||||
*/
|
||||
|
||||
static void my_timer_init_overhead(ulonglong *overhead,
|
||||
ulonglong (*cycle_timer)(void),
|
||||
ulonglong (*this_timer)(void),
|
||||
ulonglong best_timer_overhead)
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
int i;
|
||||
|
||||
/* *overhead, least of 20 calculations - cycles.overhead */
|
||||
for (i= 0, *overhead= 1000000000; i < 20; ++i)
|
||||
{
|
||||
time1= cycle_timer();
|
||||
this_timer(); /* rather than 'time_tmp= timer();' */
|
||||
time2= cycle_timer() - time1;
|
||||
if (*overhead > time2)
|
||||
*overhead= time2;
|
||||
}
|
||||
*overhead-= best_timer_overhead;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate Resolution. Called from my_timer_init().
|
||||
If a timer goes up by jumps, e.g. 1050, 1075, 1100, ...
|
||||
then the best resolution is the minimum jump, e.g. 25.
|
||||
If it's always divisible by 1000 then it's just a
|
||||
result of multiplication of a lower-precision timer
|
||||
result, e.g. nanoseconds are often microseconds * 1000.
|
||||
If the minimum jump is less than an arbitrary passed
|
||||
figure (a guess based on maximum overhead * 2), ignore.
|
||||
Usually we end up with nanoseconds = 1 because it's too
|
||||
hard to detect anything <= 100 nanoseconds.
|
||||
Often GetTickCount() has resolution = 15.
|
||||
We don't check with ticks because they take too long.
|
||||
*/
|
||||
static ulonglong my_timer_init_resolution(ulonglong (*this_timer)(void),
|
||||
ulonglong overhead_times_2)
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
ulonglong best_jump;
|
||||
int i, jumps, divisible_by_1000, divisible_by_1000000;
|
||||
|
||||
divisible_by_1000= divisible_by_1000000= 0;
|
||||
best_jump= 1000000;
|
||||
for (i= jumps= 0; jumps < 3 && i < MY_TIMER_ITERATIONS * 10; ++i)
|
||||
{
|
||||
time1= this_timer();
|
||||
time2= this_timer();
|
||||
time2-= time1;
|
||||
if (time2)
|
||||
{
|
||||
++jumps;
|
||||
if (!(time2 % 1000))
|
||||
{
|
||||
++divisible_by_1000;
|
||||
if (!(time2 % 1000000))
|
||||
++divisible_by_1000000;
|
||||
}
|
||||
if (best_jump > time2)
|
||||
best_jump= time2;
|
||||
/* For milliseconds, one jump is enough. */
|
||||
if (overhead_times_2 == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jumps == 3)
|
||||
{
|
||||
if (jumps == divisible_by_1000000)
|
||||
return 1000000;
|
||||
if (jumps == divisible_by_1000)
|
||||
return 1000;
|
||||
}
|
||||
if (best_jump > overhead_times_2)
|
||||
return best_jump;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate cycle frequency by seeing how many cycles pass
|
||||
in a 200-microsecond period. I tried with 10-microsecond
|
||||
periods originally, and the result was often very wrong.
|
||||
*/
|
||||
|
||||
static ulonglong my_timer_init_frequency(MY_TIMER_INFO *mti)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_microseconds();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS; ++i)
|
||||
{
|
||||
time3= my_timer_microseconds();
|
||||
if (time3 - time2 > 200) break;
|
||||
}
|
||||
time4= my_timer_cycles() - mti->cycles.overhead;
|
||||
time4-= mti->microseconds.overhead;
|
||||
return (mti->microseconds.frequency * (time4 - time1)) / (time3 - time2);
|
||||
}
|
||||
|
||||
/*
|
||||
Call my_timer_init before the first call to my_timer_xxx().
|
||||
If something must be initialized, it happens here.
|
||||
Set: what routine is being used e.g. "asm_x86"
|
||||
Set: function, overhead, actual frequency, resolution.
|
||||
*/
|
||||
|
||||
void my_timer_init(MY_TIMER_INFO *mti)
|
||||
{
|
||||
ulonglong (*best_timer)(void);
|
||||
ulonglong best_timer_overhead;
|
||||
ulonglong time1, time2;
|
||||
int i;
|
||||
|
||||
/* cycles */
|
||||
mti->cycles.frequency= 1000000000;
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
|
||||
#elif defined(__SUNPRO_C) && defined(__i386)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_64;
|
||||
#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_RDTSCLL;
|
||||
#elif defined(_WIN32) && defined(_M_IX86)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_WIN;
|
||||
#elif defined(_WIN64) && defined(_M_X64)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_RDTSC;
|
||||
#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
|
||||
#elif defined(__GNUC__) && defined(__ia64__)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64))
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC64;
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64))
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_I386;
|
||||
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_X86_64;
|
||||
#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC64;
|
||||
#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32;
|
||||
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE;
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME;
|
||||
#else
|
||||
mti->cycles.routine= 0;
|
||||
#endif
|
||||
|
||||
if (!mti->cycles.routine || !my_timer_cycles())
|
||||
{
|
||||
mti->cycles.routine= 0;
|
||||
mti->cycles.resolution= 0;
|
||||
mti->cycles.frequency= 0;
|
||||
mti->cycles.overhead= 0;
|
||||
}
|
||||
|
||||
/* nanoseconds */
|
||||
mti->nanoseconds.frequency= 1000000000; /* initial assumption */
|
||||
#if defined(HAVE_READ_REAL_TIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_READ_REAL_TIME;
|
||||
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_GETHRTIME;
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_CLOCK_GETTIME;
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
mti->nanoseconds.routine= MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME;
|
||||
#else
|
||||
mti->nanoseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->nanoseconds.routine || !my_timer_nanoseconds())
|
||||
{
|
||||
mti->nanoseconds.routine= 0;
|
||||
mti->nanoseconds.resolution= 0;
|
||||
mti->nanoseconds.frequency= 0;
|
||||
mti->nanoseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* microseconds */
|
||||
mti->microseconds.frequency= 1000000; /* initial assumption */
|
||||
#if defined(HAVE_GETTIMEOFDAY)
|
||||
mti->microseconds.routine= MY_TIMER_ROUTINE_GETTIMEOFDAY;
|
||||
#elif defined(_WIN32)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
/* Windows: typical frequency = 3579545, actually 1/3 microsecond. */
|
||||
if (!QueryPerformanceFrequency(&li))
|
||||
mti->microseconds.routine= 0;
|
||||
else
|
||||
{
|
||||
mti->microseconds.frequency= li.QuadPart;
|
||||
mti->microseconds.routine= MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER;
|
||||
}
|
||||
}
|
||||
#else
|
||||
mti->microseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->microseconds.routine || !my_timer_microseconds())
|
||||
{
|
||||
mti->microseconds.routine= 0;
|
||||
mti->microseconds.resolution= 0;
|
||||
mti->microseconds.frequency= 0;
|
||||
mti->microseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* milliseconds */
|
||||
mti->milliseconds.frequency= 1000; /* initial assumption */
|
||||
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_FTIME;
|
||||
#elif defined(_WIN32)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME;
|
||||
#elif defined(HAVE_TIME)
|
||||
mti->milliseconds.routine= MY_TIMER_ROUTINE_TIME;
|
||||
#else
|
||||
mti->milliseconds.routine= 0;
|
||||
#endif
|
||||
if (!mti->milliseconds.routine || !my_timer_milliseconds())
|
||||
{
|
||||
mti->milliseconds.routine= 0;
|
||||
mti->milliseconds.resolution= 0;
|
||||
mti->milliseconds.frequency= 0;
|
||||
mti->milliseconds.overhead= 0;
|
||||
}
|
||||
|
||||
/* ticks */
|
||||
mti->ticks.frequency= 100; /* permanent assumption */
|
||||
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
|
||||
mti->ticks.routine= MY_TIMER_ROUTINE_TIMES;
|
||||
#elif defined(_WIN32)
|
||||
mti->ticks.routine= MY_TIMER_ROUTINE_GETTICKCOUNT;
|
||||
#else
|
||||
mti->ticks.routine= 0;
|
||||
#endif
|
||||
if (!mti->ticks.routine || !my_timer_ticks())
|
||||
{
|
||||
mti->ticks.routine= 0;
|
||||
mti->ticks.resolution= 0;
|
||||
mti->ticks.frequency= 0;
|
||||
mti->ticks.overhead= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate overhead in terms of the timer that
|
||||
gives the best resolution: cycles or nanoseconds.
|
||||
I doubt it ever will be as bad as microseconds.
|
||||
*/
|
||||
if (mti->cycles.routine)
|
||||
best_timer= &my_timer_cycles;
|
||||
else
|
||||
{
|
||||
if (mti->nanoseconds.routine)
|
||||
{
|
||||
best_timer= &my_timer_nanoseconds;
|
||||
}
|
||||
else
|
||||
best_timer= &my_timer_microseconds;
|
||||
}
|
||||
|
||||
/* best_timer_overhead = least of 20 calculations */
|
||||
for (i= 0, best_timer_overhead= 1000000000; i < 20; ++i)
|
||||
{
|
||||
time1= best_timer();
|
||||
time2= best_timer() - time1;
|
||||
if (best_timer_overhead > time2)
|
||||
best_timer_overhead= time2;
|
||||
}
|
||||
if (mti->cycles.routine)
|
||||
my_timer_init_overhead(&mti->cycles.overhead,
|
||||
best_timer,
|
||||
&my_timer_cycles,
|
||||
best_timer_overhead);
|
||||
if (mti->nanoseconds.routine)
|
||||
my_timer_init_overhead(&mti->nanoseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_nanoseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->microseconds.routine)
|
||||
my_timer_init_overhead(&mti->microseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_microseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->milliseconds.routine)
|
||||
my_timer_init_overhead(&mti->milliseconds.overhead,
|
||||
best_timer,
|
||||
&my_timer_milliseconds,
|
||||
best_timer_overhead);
|
||||
if (mti->ticks.routine)
|
||||
my_timer_init_overhead(&mti->ticks.overhead,
|
||||
best_timer,
|
||||
&my_timer_ticks,
|
||||
best_timer_overhead);
|
||||
|
||||
/*
|
||||
Calculate resolution for nanoseconds or microseconds
|
||||
or milliseconds, by seeing if it's always divisible
|
||||
by 1000, and by noticing how much jumping occurs.
|
||||
For ticks, just assume the resolution is 1.
|
||||
*/
|
||||
if (mti->cycles.routine)
|
||||
mti->cycles.resolution= 1;
|
||||
if (mti->nanoseconds.routine)
|
||||
mti->nanoseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_nanoseconds, 20000);
|
||||
if (mti->microseconds.routine)
|
||||
mti->microseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_microseconds, 20);
|
||||
if (mti->milliseconds.routine)
|
||||
{
|
||||
if (mti->milliseconds.routine == MY_TIMER_ROUTINE_TIME)
|
||||
mti->milliseconds.resolution= 1000;
|
||||
else
|
||||
mti->milliseconds.resolution=
|
||||
my_timer_init_resolution(&my_timer_milliseconds, 0);
|
||||
}
|
||||
if (mti->ticks.routine)
|
||||
mti->ticks.resolution= 1;
|
||||
|
||||
/*
|
||||
Calculate cycles frequency,
|
||||
if we have both a cycles routine and a microseconds routine.
|
||||
In tests, this usually results in a figure within 2% of
|
||||
what "cat /proc/cpuinfo" says.
|
||||
If the microseconds routine is QueryPerformanceCounter
|
||||
(i.e. it's Windows), and the microseconds frequency is >
|
||||
500,000,000 (i.e. it's Windows Server so it uses RDTSC)
|
||||
and the microseconds resolution is > 100 (i.e. dreadful),
|
||||
then calculate cycles frequency = microseconds frequency.
|
||||
*/
|
||||
if (mti->cycles.routine
|
||||
&& mti->microseconds.routine)
|
||||
{
|
||||
if (mti->microseconds.routine ==
|
||||
MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER
|
||||
&& mti->microseconds.frequency > 500000000
|
||||
&& mti->microseconds.resolution > 100)
|
||||
mti->cycles.frequency= mti->microseconds.frequency;
|
||||
else
|
||||
{
|
||||
ulonglong time1, time2;
|
||||
time1= my_timer_init_frequency(mti);
|
||||
/* Repeat once in case there was an interruption. */
|
||||
time2= my_timer_init_frequency(mti);
|
||||
if (time1 < time2) mti->cycles.frequency= time1;
|
||||
else mti->cycles.frequency= time2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate milliseconds frequency =
|
||||
(cycles-frequency/#-of-cycles) * #-of-milliseconds,
|
||||
if we have both a milliseconds routine and a cycles
|
||||
routine.
|
||||
This will be inaccurate if milliseconds resolution > 1.
|
||||
This is probably only useful when testing new platforms.
|
||||
*/
|
||||
if (mti->milliseconds.routine
|
||||
&& mti->milliseconds.resolution < 1000
|
||||
&& mti->microseconds.routine
|
||||
&& mti->cycles.routine)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_milliseconds();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
|
||||
{
|
||||
time3= my_timer_milliseconds();
|
||||
if (time3 - time2 > 10) break;
|
||||
}
|
||||
time4= my_timer_cycles();
|
||||
mti->milliseconds.frequency=
|
||||
(mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate ticks.frequency =
|
||||
(cycles-frequency/#-of-cycles * #-of-ticks,
|
||||
if we have both a ticks routine and a cycles
|
||||
routine,
|
||||
This is probably only useful when testing new platforms.
|
||||
*/
|
||||
if (mti->ticks.routine
|
||||
&& mti->microseconds.routine
|
||||
&& mti->cycles.routine)
|
||||
{
|
||||
int i;
|
||||
ulonglong time1, time2, time3, time4;
|
||||
time1= my_timer_cycles();
|
||||
time2= my_timer_ticks();
|
||||
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
|
||||
for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
|
||||
{
|
||||
time3= my_timer_ticks();
|
||||
if (time3 - time2 > 10) break;
|
||||
}
|
||||
time4= my_timer_cycles();
|
||||
mti->ticks.frequency=
|
||||
(mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Additional Comments
|
||||
-------------------
|
||||
|
||||
This is for timing, i.e. finding out how long a piece of code
|
||||
takes. If you want time of day matching a wall clock, the
|
||||
my_timer_xxx functions won't help you.
|
||||
|
||||
The best timer is the one with highest frequency, lowest
|
||||
overhead, and resolution=1. The my_timer_info() routine will tell
|
||||
you at runtime which timer that is. Usually it will be
|
||||
my_timer_cycles() but be aware that, although it's best,
|
||||
it has possible flaws and dangers. Depending on platform:
|
||||
- The frequency might change. We don't test for this. It
|
||||
happens on laptops for power saving, and on blade servers
|
||||
for avoiding overheating.
|
||||
- The overhead that my_timer_init() returns is the minimum.
|
||||
In fact it could be slightly greater because of caching or
|
||||
because you call the routine by address, as recommended.
|
||||
It could be hugely greater if there's an interrupt.
|
||||
- The x86 cycle counter, RDTSC doesn't "serialize". That is,
|
||||
if there is out-of-order execution, rdtsc might be processed
|
||||
after an instruction that logically follows it.
|
||||
(We could force serialization, but that would be slower.)
|
||||
- It is possible to set a flag which renders RDTSC
|
||||
inoperative. Somebody responsible for the kernel
|
||||
of the operating system would have to make this
|
||||
decision. For the platforms we've tested with, there's
|
||||
no such problem.
|
||||
- With a multi-processor arrangement, it's possible
|
||||
to get the cycle count from one processor in
|
||||
thread X, and the cycle count from another processor
|
||||
in thread Y. They may not always be in synch.
|
||||
- You can't depend on a cycle counter being available for
|
||||
all platforms. On Alphas, the
|
||||
cycle counter is only 32-bit, so it would overflow quickly,
|
||||
so we don't bother with it. On platforms that we haven't
|
||||
tested, there might be some if/endif combination that we
|
||||
didn't expect, or some assembler routine that we didn't
|
||||
supply.
|
||||
|
||||
The recommended way to use the timer routines is:
|
||||
1. Somewhere near the beginning of the program, call
|
||||
my_timer_init(). This should only be necessary once,
|
||||
although you can call it again if you think that the
|
||||
frequency has changed.
|
||||
2. Determine the best timer based on frequency, resolution,
|
||||
overhead -- all things that my_timer_init() returns.
|
||||
Preserve the address of the timer and the my_timer_into
|
||||
results in an easily-accessible place.
|
||||
3. Instrument the code section that you're monitoring, thus:
|
||||
time1= my_timer_xxx();
|
||||
Instrumented code;
|
||||
time2= my_timer_xxx();
|
||||
elapsed_time= (time2 - time1) - overhead;
|
||||
If the timer is always on, then overhead is always there,
|
||||
so don't subtract it.
|
||||
4. Save the elapsed time, or add it to a totaller.
|
||||
5. When all timing processes are complete, transfer the
|
||||
saved / totalled elapsed time to permanent storage.
|
||||
Optionally you can convert cycles to microseconds at
|
||||
this point. (Don't do so every time you calculate
|
||||
elapsed_time! That would waste time and lose precision!)
|
||||
For converting cycles to microseconds, use the frequency
|
||||
that my_timer_init() returns. You'll also need to convert
|
||||
if the my_timer_microseconds() function is the Windows
|
||||
function QueryPerformanceCounter(), since that's sometimes
|
||||
a counter with precision slightly better than microseconds.
|
||||
|
||||
Since we recommend calls by function pointer, we supply
|
||||
no inline functions.
|
||||
|
||||
Some comments on the many candidate routines for timing ...
|
||||
|
||||
clock() -- We don't use because it would overflow frequently.
|
||||
|
||||
clock_gettime() -- In tests, clock_gettime often had
|
||||
resolution = 1000.
|
||||
|
||||
ftime() -- A "man ftime" says: "This function is obsolete.
|
||||
Don't use it." On every platform that we tested, if ftime()
|
||||
was available, then so was gettimeofday(), and gettimeofday()
|
||||
overhead was always at least as good as ftime() overhead.
|
||||
|
||||
gettimeofday() -- available on most platforms, though not
|
||||
on Windows. There is a hardware timer (sometimes a Programmable
|
||||
Interrupt Timer or "PIT") (sometimes a "HPET") used for
|
||||
interrupt generation. When it interrupts (a "tick" or "jiffy",
|
||||
typically 1 centisecond) it sets xtime. For gettimeofday, a
|
||||
Linux kernel routine usually gets xtime and then gets rdtsc
|
||||
to get elapsed nanoseconds since the last tick. On Red Hat
|
||||
Enterprise Linux 3, there was once a bug which caused the
|
||||
resolution to be 1000, i.e. one centisecond. We never check
|
||||
for time-zone change.
|
||||
|
||||
getnstimeofday() -- something to watch for in future Linux
|
||||
|
||||
do_gettimeofday() -- exists on Linux but not for "userland"
|
||||
|
||||
get_cycles() -- a multi-platform function, worth watching
|
||||
in future Linux versions. But we found platform-specific
|
||||
functions which were better documented in operating-system
|
||||
manuals. And get_cycles() can fail or return a useless
|
||||
32-bit number. It might be available on some platforms,
|
||||
such as arm, which we didn't test. Using
|
||||
"include <linux/timex.h>" or "include <asm/timex.h>"
|
||||
can lead to autoconf or compile errors, depending on system.
|
||||
|
||||
rdtsc, __rdtsc, rdtscll: available for x86 with Linux BSD,
|
||||
Solaris, Windows. See "possible flaws and dangers" comments.
|
||||
|
||||
times(): what we use for ticks. Should just read the last
|
||||
(xtime) tick count, therefore should be fast, but usually
|
||||
isn't.
|
||||
|
||||
GetTickCount(): we use this for my_timer_ticks() on
|
||||
Windows. Actually it really is a tick counter, so resolution
|
||||
>= 10 milliseconds unless you have a very old Windows version.
|
||||
With Windows 95 or 98 or ME, timeGetTime() has better resolution than
|
||||
GetTickCount (1ms rather than 55ms). But with Windows NT or XP or 2000,
|
||||
they're both getting from a variable in the Process Environment Block
|
||||
(PEB), and the variable is set by the programmable interrupt timer, so
|
||||
the resolution is the same (usually 10-15 milliseconds). Also timeGetTime
|
||||
is slower on old machines:
|
||||
http://www.doumo.jp/aon-java/jsp/postgretips/tips.jsp?tips=74.
|
||||
Also timeGetTime requires linking winmm.lib,
|
||||
Therefore we use GetTickCount.
|
||||
It will overflow every 49 days because the return is 32-bit.
|
||||
There is also a GetTickCount64 but it requires Vista or Windows Server 2008.
|
||||
(As for GetSystemTimeAsFileTime, its precision is spurious, it
|
||||
just reads the tick variable like the other functions do.
|
||||
However, we don't expect it to overflow every 49 days, so we
|
||||
will prefer it for my_timer_milliseconds().)
|
||||
|
||||
QueryPerformanceCounter() we use this for my_timer_microseconds()
|
||||
on Windows. 1-PIT-tick (often 1/3-microsecond). Usually reads
|
||||
the PIT so it's slow. On some Windows variants, uses RDTSC.
|
||||
|
||||
GetLocalTime() this is available on Windows but we don't use it.
|
||||
|
||||
getclock(): documented for Alpha, but not found during tests.
|
||||
|
||||
mach_absolute_time() and UpTime() are recommended for Apple.
|
||||
Inititally they weren't tried, because asm_ppc seems to do the job.
|
||||
But now we use mach_absolute_time for nanoseconds.
|
||||
|
||||
Any clock-based timer can be affected by NPT (ntpd program),
|
||||
which means:
|
||||
- full-second correction can occur for leap second
|
||||
- tiny corrections can occcur approimately every 11 minutes
|
||||
(but I think they only affect the RTC which isn't the PIT).
|
||||
|
||||
We define "precision" as "frequency" and "high precision" is
|
||||
"frequency better than 1 microsecond". We define "resolution"
|
||||
as a synonym for "granularity". We define "accuracy" as
|
||||
"closeness to the truth" as established by some authoritative
|
||||
clock, but we can't measure accuracy.
|
||||
|
||||
Do not expect any of our timers to be monotonic; we
|
||||
won't guarantee that they return constantly-increasing
|
||||
unique numbers.
|
||||
|
||||
We tested with AIX, Solaris (x86 + Sparc), Linux (x86 +
|
||||
Itanium), Windows, 64-bit Windows, QNX, FreeBSD, HPUX,
|
||||
Irix, Mac. We didn't test with SCO.
|
||||
|
||||
*/
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <my_base.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/*
|
||||
Read a chunk of bytes from a file with retry's if needed
|
||||
|
||||
@@ -37,27 +37,36 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t readbytes, save_count;
|
||||
DBUG_ENTER("my_read");
|
||||
DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
|
||||
Filedes, (long) Buffer, (ulong) Count, MyFlags));
|
||||
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, Buffer, (ulong) Count, MyFlags));
|
||||
save_count= Count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
errno= 0; /* Linux doesn't reset this */
|
||||
if ((readbytes= read(Filedes, Buffer, (uint) Count)) != Count)
|
||||
errno= 0; /* Linux, Windows don't reset this on EOF/success */
|
||||
#ifdef _WIN32
|
||||
readbytes= my_win_read(Filedes, Buffer, Count);
|
||||
#else
|
||||
readbytes= read(Filedes, Buffer, Count);
|
||||
#endif
|
||||
|
||||
if (readbytes != Count)
|
||||
{
|
||||
my_errno= errno ? errno : -1;
|
||||
my_errno= errno;
|
||||
if (errno == 0 || (readbytes != (size_t) -1 &&
|
||||
(MyFlags & (MY_NABP | MY_FNABP))))
|
||||
my_errno= HA_ERR_FILE_TOO_SHORT;
|
||||
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
|
||||
(int) readbytes, (ulong) Count, Filedes,
|
||||
my_errno));
|
||||
#ifdef THREAD
|
||||
|
||||
if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_read() was interrupted and returned %ld",
|
||||
(long) readbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
|
||||
{
|
||||
if (readbytes == (size_t) -1)
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
|
||||
#undef SAFEMALLOC
|
||||
#endif
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
/* My memory re allocator */
|
||||
|
||||
/**
|
||||
@brief wrapper around realloc()
|
||||
|
||||
@param oldpoint pointer to currently allocated area
|
||||
@param size new size requested, must be >0
|
||||
@param my_flags flags
|
||||
|
||||
@note if size==0 realloc() may return NULL; my_realloc() treats this as an
|
||||
error which is not the intention of realloc()
|
||||
*/
|
||||
void* my_realloc(void* oldpoint, size_t size, myf my_flags)
|
||||
{
|
||||
void *point;
|
||||
DBUG_ENTER("my_realloc");
|
||||
DBUG_PRINT("my",("ptr: 0x%lx size: %lu my_flags: %d", (long) oldpoint,
|
||||
(ulong) size, my_flags));
|
||||
|
||||
DBUG_ASSERT(size > 0);
|
||||
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
|
||||
DBUG_RETURN(my_malloc(size,my_flags));
|
||||
#ifdef USE_HALLOC
|
||||
if (!(point = malloc(size)))
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint,my_flags);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & MY_FAE+MY_WME)
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(point,oldpoint,size);
|
||||
free(oldpoint);
|
||||
}
|
||||
#else
|
||||
if ((point= (uchar*) realloc(oldpoint,size)) == NULL)
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint, my_flags);
|
||||
if (my_flags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(oldpoint);
|
||||
my_errno=errno;
|
||||
if (my_flags & (MY_FAE+MY_WME))
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), size);
|
||||
}
|
||||
#endif
|
||||
DBUG_PRINT("exit",("ptr: 0x%lx", (long) point));
|
||||
DBUG_RETURN(point);
|
||||
} /* my_realloc */
|
||||
@@ -0,0 +1,124 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_dir.h>
|
||||
#include <m_string.h>
|
||||
#include "mysys_err.h"
|
||||
#if defined(HAVE_UTIME_H)
|
||||
#include <utime.h>
|
||||
#elif defined(HAVE_SYS_UTIME_H)
|
||||
#include <sys/utime.h>
|
||||
#elif !defined(HPUX10)
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
Rename with copy stat form old file
|
||||
Copy stats from old file to new file, deletes orginal and
|
||||
changes new file name to old file name
|
||||
|
||||
if MY_REDEL_MAKE_COPY is given, then the orginal file
|
||||
is renamed to org_name-'current_time'.BAK
|
||||
*/
|
||||
|
||||
#define REDEL_EXT ".BAK"
|
||||
|
||||
int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
|
||||
{
|
||||
int error=1;
|
||||
DBUG_ENTER("my_redel");
|
||||
DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s' MyFlags: %d",
|
||||
org_name,tmp_name,MyFlags));
|
||||
|
||||
if (my_copystat(org_name,tmp_name,MyFlags) < 0)
|
||||
goto end;
|
||||
if (MyFlags & MY_REDEL_MAKE_BACKUP)
|
||||
{
|
||||
char name_buff[FN_REFLEN+20];
|
||||
char ext[20];
|
||||
ext[0]='-';
|
||||
get_date(ext+1,2+4,(time_t) 0);
|
||||
strmov(strend(ext),REDEL_EXT);
|
||||
if (my_rename(org_name, fn_format(name_buff, org_name, "", ext, 2),
|
||||
MyFlags))
|
||||
goto end;
|
||||
}
|
||||
else if (my_delete_allow_opened(org_name, MyFlags))
|
||||
goto end;
|
||||
if (my_rename(tmp_name,org_name,MyFlags))
|
||||
goto end;
|
||||
|
||||
error=0;
|
||||
end:
|
||||
DBUG_RETURN(error);
|
||||
} /* my_redel */
|
||||
|
||||
|
||||
/* Copy stat from one file to another */
|
||||
/* Return -1 if can't get stat, 1 if wrong type of file */
|
||||
|
||||
int my_copystat(const char *from, const char *to, int MyFlags)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat(from, &statbuf))
|
||||
{
|
||||
my_errno=errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),from,errno);
|
||||
return -1; /* Can't get stat on input file */
|
||||
}
|
||||
if ((statbuf.st_mode & S_IFMT) != S_IFREG)
|
||||
return 1;
|
||||
|
||||
/* Copy modes */
|
||||
if (chmod(to, statbuf.st_mode & 07777))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(__WIN__)
|
||||
if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING)
|
||||
{
|
||||
if (MyFlags & MY_LINK_WARNING)
|
||||
my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink);
|
||||
}
|
||||
/* Copy ownership */
|
||||
if (chown(to, statbuf.st_uid, statbuf.st_gid))
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno);
|
||||
return -1;
|
||||
}
|
||||
#endif /* !__WIN__ */
|
||||
|
||||
if (MyFlags & MY_COPYTIME)
|
||||
{
|
||||
struct utimbuf timep;
|
||||
timep.actime = statbuf.st_atime;
|
||||
timep.modtime = statbuf.st_mtime;
|
||||
(void) utime((char*) to, &timep);/* Update last accessed and modified times */
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* my_copystat */
|
||||
@@ -44,7 +44,7 @@ int my_rename(const char *from, const char *to, myf MyFlags)
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RENAME)
|
||||
#if defined(__WIN__) || defined(__NETWARE__)
|
||||
#if defined(__WIN__)
|
||||
/*
|
||||
On windows we can't rename over an existing file:
|
||||
Remove any conflicting files:
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
/*
|
||||
Seek to a position in a file.
|
||||
@@ -42,39 +43,34 @@
|
||||
actual error.
|
||||
*/
|
||||
|
||||
my_off_t my_seek(File fd, my_off_t pos, int whence,
|
||||
myf MyFlags __attribute__((unused)))
|
||||
my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
|
||||
{
|
||||
reg1 os_off_t newpos= -1;
|
||||
os_off_t newpos= -1;
|
||||
DBUG_ENTER("my_seek");
|
||||
DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
|
||||
fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos,
|
||||
whence, MyFlags));
|
||||
DBUG_PRINT("my",("fd: %d Pos: %llu Whence: %d MyFlags: %d",
|
||||
fd, (ulonglong) pos, whence, MyFlags));
|
||||
DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */
|
||||
|
||||
/*
|
||||
Make sure we are using a valid file descriptor!
|
||||
*/
|
||||
DBUG_ASSERT(fd != -1);
|
||||
#if defined(THREAD) && !defined(HAVE_PREAD)
|
||||
if (MyFlags & MY_THREADSAFE)
|
||||
{
|
||||
pthread_mutex_lock(&my_file_info[fd].mutex);
|
||||
newpos= lseek(fd, pos, whence);
|
||||
pthread_mutex_unlock(&my_file_info[fd].mutex);
|
||||
}
|
||||
else
|
||||
#if defined (_WIN32)
|
||||
newpos= my_win_lseek(fd, pos, whence);
|
||||
#else
|
||||
newpos= lseek(fd, pos, whence);
|
||||
#endif
|
||||
newpos= lseek(fd, pos, whence);
|
||||
if (newpos == (os_off_t) -1)
|
||||
{
|
||||
my_errno=errno;
|
||||
DBUG_PRINT("error",("lseek: %lu errno: %d", (ulong) newpos,errno));
|
||||
my_errno= errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_SEEK, MYF(0), my_filename(fd), my_errno);
|
||||
DBUG_PRINT("error", ("lseek: %llu errno: %d", (ulonglong) newpos, errno));
|
||||
DBUG_RETURN(MY_FILEPOS_ERROR);
|
||||
}
|
||||
if ((my_off_t) newpos != pos)
|
||||
{
|
||||
DBUG_PRINT("exit",("pos: %lu", (ulong) newpos));
|
||||
DBUG_PRINT("exit",("pos: %llu", (ulonglong) newpos));
|
||||
}
|
||||
DBUG_RETURN((my_off_t) newpos);
|
||||
} /* my_seek */
|
||||
@@ -83,19 +79,24 @@ my_off_t my_seek(File fd, my_off_t pos, int whence,
|
||||
/* Tell current position of file */
|
||||
/* ARGSUSED */
|
||||
|
||||
my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
|
||||
my_off_t my_tell(File fd, myf MyFlags)
|
||||
{
|
||||
os_off_t pos;
|
||||
DBUG_ENTER("my_tell");
|
||||
DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
|
||||
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
|
||||
DBUG_ASSERT(fd >= 0);
|
||||
#ifdef HAVE_TELL
|
||||
pos=tell(fd);
|
||||
#if defined (HAVE_TELL) && !defined (_WIN32)
|
||||
pos= tell(fd);
|
||||
#else
|
||||
pos=lseek(fd, 0L, MY_SEEK_CUR);
|
||||
pos= my_seek(fd, 0L, MY_SEEK_CUR,0);
|
||||
#endif
|
||||
if (pos == (os_off_t) -1)
|
||||
my_errno=errno;
|
||||
DBUG_PRINT("exit",("pos: %lu", (ulong) pos));
|
||||
{
|
||||
my_errno= errno;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_CANT_SEEK, MYF(0), my_filename(fd), my_errno);
|
||||
DBUG_PRINT("error", ("tell: %llu errno: %d", (ulonglong) pos, my_errno));
|
||||
}
|
||||
DBUG_PRINT("exit",("pos: %llu", (ulonglong) pos));
|
||||
DBUG_RETURN((my_off_t) pos);
|
||||
} /* my_tell */
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
|
||||
void my_sleep(ulong m_seconds)
|
||||
{
|
||||
#ifdef __NETWARE__
|
||||
delay(m_seconds/1000+1);
|
||||
#elif defined(__WIN__)
|
||||
#if defined(__WIN__)
|
||||
Sleep(m_seconds/1000+1); /* Sleep() has millisecond arg */
|
||||
#elif defined(HAVE_SELECT)
|
||||
struct timeval t;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -27,25 +27,20 @@ my_bool timed_mutexes= 0;
|
||||
/* from my_init */
|
||||
char * home_dir=0;
|
||||
const char *my_progname=0;
|
||||
char NEAR curr_dir[FN_REFLEN]= {0},
|
||||
NEAR home_dir_buff[FN_REFLEN]= {0};
|
||||
char curr_dir[FN_REFLEN]= {0},
|
||||
home_dir_buff[FN_REFLEN]= {0};
|
||||
ulong my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
|
||||
ulong my_file_total_opened= 0;
|
||||
int NEAR my_umask=0664, NEAR my_umask_dir=0777;
|
||||
#ifndef THREAD
|
||||
int NEAR my_errno=0;
|
||||
#endif
|
||||
struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}};
|
||||
int my_umask=0664, my_umask_dir=0777;
|
||||
|
||||
struct st_my_file_info my_file_info_default[MY_NFILE];
|
||||
uint my_file_limit= MY_NFILE;
|
||||
struct st_my_file_info *my_file_info= my_file_info_default;
|
||||
|
||||
/* From mf_brkhant */
|
||||
int NEAR my_dont_interrupt=0;
|
||||
int my_dont_interrupt=0;
|
||||
volatile int _my_signals=0;
|
||||
struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
|
||||
#ifdef THREAD
|
||||
sigset_t my_signals; /* signals blocked by mf_brkhant */
|
||||
#endif
|
||||
|
||||
/* from mf_reccache.c */
|
||||
ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
|
||||
@@ -65,32 +60,32 @@ my_bool my_use_large_pages= 0;
|
||||
uint my_large_page_size= 0;
|
||||
#endif
|
||||
|
||||
/* from safe_malloc */
|
||||
uint sf_malloc_prehunc=0, /* If you have problem with core- */
|
||||
sf_malloc_endhunc=0, /* dump when malloc-message.... */
|
||||
/* set theese to 64 or 128 */
|
||||
sf_malloc_quick=0; /* set if no calls to sanity */
|
||||
size_t sf_malloc_cur_memory= 0L; /* Current memory usage */
|
||||
size_t sf_malloc_max_memory= 0L; /* Maximum memory usage */
|
||||
uint sf_malloc_count= 0; /* Number of times NEW() was called */
|
||||
uchar *sf_min_adress= (uchar*) ~(unsigned long) 0L,
|
||||
*sf_max_adress= (uchar*) 0L;
|
||||
/* Root of the linked list of struct st_irem */
|
||||
struct st_irem *sf_malloc_root = NULL;
|
||||
|
||||
/* from my_alarm */
|
||||
int volatile my_have_got_alarm=0; /* declare variable to reset */
|
||||
ulong my_time_to_wait_for_lock=2; /* In seconds */
|
||||
|
||||
/* from errors.c */
|
||||
#ifdef SHARED_LIBRARY
|
||||
char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
|
||||
const char *globerrs[GLOBERRS]; /* my_error_messages is here */
|
||||
#endif
|
||||
void (*my_abort_hook)(int) = (void(*)(int)) exit;
|
||||
int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
|
||||
my_message_no_curses;
|
||||
int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
|
||||
my_message_no_curses;
|
||||
void (*error_handler_hook)(uint error, const char *str, myf MyFlags)=
|
||||
my_message_stderr;
|
||||
void (*fatal_error_handler_hook)(uint error, const char *str, myf MyFlags)=
|
||||
my_message_stderr;
|
||||
|
||||
static const char *proc_info_dummy(void *a __attribute__((unused)),
|
||||
const char *b __attribute__((unused)),
|
||||
const char *c __attribute__((unused)),
|
||||
const char *d __attribute__((unused)),
|
||||
const unsigned int e __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is to be able to call set_thd_proc_info from the C code */
|
||||
const char *(*proc_info_hook)(void *, const char *, const char *, const char *,
|
||||
const unsigned int)= proc_info_dummy;
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/**
|
||||
@@ -106,8 +101,35 @@ ulonglong query_performance_frequency, query_performance_offset;
|
||||
#endif
|
||||
|
||||
/* How to disable options */
|
||||
my_bool NEAR my_disable_locking=0;
|
||||
my_bool NEAR my_disable_async_io=0;
|
||||
my_bool NEAR my_disable_flush_key_blocks=0;
|
||||
my_bool NEAR my_disable_symlinks=0;
|
||||
my_bool NEAR mysys_uses_curses=0;
|
||||
my_bool my_disable_locking=0;
|
||||
my_bool my_disable_async_io=0;
|
||||
my_bool my_disable_flush_key_blocks=0;
|
||||
my_bool my_disable_symlinks=0;
|
||||
|
||||
/*
|
||||
Note that PSI_hook and PSI_server are unconditionally
|
||||
(no ifdef HAVE_PSI_INTERFACE) defined.
|
||||
This is to ensure binary compatibility between the server and plugins,
|
||||
in the case when:
|
||||
- the server is not compiled with HAVE_PSI_INTERFACE
|
||||
- a plugin is compiled with HAVE_PSI_INTERFACE
|
||||
See the doxygen documentation for the performance schema.
|
||||
*/
|
||||
|
||||
/**
|
||||
Hook for the instrumentation interface.
|
||||
Code implementing the instrumentation interface should register here.
|
||||
*/
|
||||
struct PSI_bootstrap *PSI_hook= NULL;
|
||||
|
||||
/**
|
||||
Instance of the instrumentation interface for the MySQL server.
|
||||
@todo This is currently a global variable, which is handy when
|
||||
compiling instrumented code that is bundled with the server.
|
||||
When dynamic plugin are truly supported, this variable will need
|
||||
to be replaced by a macro, so that each XYZ plugin can have it's own
|
||||
xyz_psi_server variable, obtained from PSI_bootstrap::get_interface()
|
||||
with the version used at compile time for plugin XYZ.
|
||||
*/
|
||||
PSI *PSI_server= NULL;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef MYSYS_MY_STATIC_INCLUDED
|
||||
#define MYSYS_MY_STATIC_INCLUDED
|
||||
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,35 +25,13 @@ C_MODE_START
|
||||
#include <signal.h>
|
||||
|
||||
#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
|
||||
#define MIN_KEYBLOCK (min(IO_SIZE,1024))
|
||||
#define MAX_KEYBLOCK 8192 /* Max keyblocklength == 8*IO_SIZE */
|
||||
#define MAX_BLOCK_TYPES MAX_KEYBLOCK/MIN_KEYBLOCK
|
||||
|
||||
struct st_remember {
|
||||
int number;
|
||||
sig_handler (*func)(int number);
|
||||
};
|
||||
|
||||
/*
|
||||
Structure that stores information of a allocated memory block
|
||||
The data is at &struct_adr+sizeof(ALIGN_SIZE(sizeof(struct irem)))
|
||||
The lspecialvalue is at the previous 4 bytes from this, which may not
|
||||
necessarily be in the struct if the struct size isn't aligned at a 8 byte
|
||||
boundary.
|
||||
*/
|
||||
|
||||
struct st_irem
|
||||
{
|
||||
struct st_irem *next; /* Linked list of structures */
|
||||
struct st_irem *prev; /* Other link */
|
||||
char *filename; /* File in which memory was new'ed */
|
||||
size_t datasize; /* Size requested */
|
||||
uint32 linenum; /* Line number in above file */
|
||||
uint32 SpecialValue; /* Underrun marker value */
|
||||
};
|
||||
|
||||
|
||||
extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN];
|
||||
extern char curr_dir[FN_REFLEN], home_dir_buff[FN_REFLEN];
|
||||
|
||||
extern volatile int _my_signals;
|
||||
extern struct st_remember _my_sig_remember[MAX_SIGNALS];
|
||||
@@ -60,15 +41,10 @@ extern const char *soundex_map;
|
||||
extern USED_MEM* my_once_root_block;
|
||||
extern uint my_once_extra;
|
||||
|
||||
extern uchar *sf_min_adress,*sf_max_adress;
|
||||
extern uint sf_malloc_count;
|
||||
extern struct st_irem *sf_malloc_root;
|
||||
|
||||
extern struct st_my_file_info my_file_info_default[MY_NFILE];
|
||||
|
||||
extern ulonglong query_performance_frequency, query_performance_offset;
|
||||
|
||||
#if defined(THREAD) && !defined(__WIN__)
|
||||
extern sigset_t my_signals; /* signals blocked by mf_brkhant */
|
||||
#endif
|
||||
C_MODE_END
|
||||
|
||||
#endif /* MYSYS_MY_STATIC_INCLUDED */
|
||||
|
||||
@@ -113,14 +113,12 @@ int my_is_symlink(const char *filename __attribute__((unused)))
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Resolve all symbolic links in path
|
||||
'to' may be equal to 'filename'
|
||||
*/
|
||||
|
||||
int my_realpath(char *to, const char *filename,
|
||||
myf MyFlags __attribute__((unused)))
|
||||
int my_realpath(char *to, const char *filename, myf MyFlags)
|
||||
{
|
||||
#if defined(HAVE_REALPATH) && !defined(HAVE_BROKEN_REALPATH)
|
||||
int result=0;
|
||||
@@ -146,8 +144,24 @@ int my_realpath(char *to, const char *filename,
|
||||
result= -1;
|
||||
}
|
||||
DBUG_RETURN(result);
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
int ret= GetFullPathName(filename,FN_REFLEN,
|
||||
to,
|
||||
NULL);
|
||||
if (ret == 0 || ret > FN_REFLEN)
|
||||
{
|
||||
if (ret > FN_REFLEN)
|
||||
my_errno= ENAMETOOLONG;
|
||||
else
|
||||
my_errno= EACCES;
|
||||
if (MyFlags & MY_WME)
|
||||
my_error(EE_REALPATH, MYF(0), filename, my_errno);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
my_load_path(to, filename, NullS);
|
||||
#endif
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ int my_sync(File fd, myf my_flags)
|
||||
/* Some file systems don't support F_FULLFSYNC and fail above: */
|
||||
DBUG_PRINT("info",("fcntl(F_FULLFSYNC) failed, falling back"));
|
||||
#endif
|
||||
#if defined(HAVE_FDATASYNC)
|
||||
#if defined(HAVE_FDATASYNC) && HAVE_DECL_FDATASYNC
|
||||
res= fdatasync(fd);
|
||||
#elif defined(HAVE_FSYNC)
|
||||
res= fsync(fd);
|
||||
#elif defined(__WIN__)
|
||||
res= _commit(fd);
|
||||
#elif defined(_WIN32)
|
||||
res= my_win_fsync(fd);
|
||||
#else
|
||||
#error Cannot find a way to sync a file, durability in danger
|
||||
res= 0; /* No sync (strange OS) */
|
||||
@@ -89,6 +89,8 @@ int my_sync(File fd, myf my_flags)
|
||||
|
||||
|
||||
static const char cur_dir_name[]= {FN_CURLIB, 0};
|
||||
|
||||
|
||||
/*
|
||||
Force directory information to disk.
|
||||
|
||||
@@ -100,9 +102,11 @@ static const char cur_dir_name[]= {FN_CURLIB, 0};
|
||||
RETURN
|
||||
0 if ok, !=0 if error
|
||||
*/
|
||||
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
|
||||
int my_sync_dir(const char *dir_name, myf my_flags)
|
||||
{
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
File dir_fd;
|
||||
int res= 0;
|
||||
const char *correct_dir_name;
|
||||
@@ -124,11 +128,18 @@ int my_sync_dir(const char *dir_name, myf my_flags)
|
||||
else
|
||||
res= 1;
|
||||
DBUG_RETURN(res);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
int my_sync_dir(const char *dir_name __attribute__((unused)),
|
||||
myf my_flags __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
|
||||
/*
|
||||
Force directory information to disk.
|
||||
@@ -141,15 +152,24 @@ int my_sync_dir(const char *dir_name, myf my_flags)
|
||||
RETURN
|
||||
0 if ok, !=0 if error
|
||||
*/
|
||||
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
|
||||
int my_sync_dir_by_file(const char *file_name, myf my_flags)
|
||||
{
|
||||
#ifdef NEED_EXPLICIT_SYNC_DIR
|
||||
char dir_name[FN_REFLEN];
|
||||
size_t dir_name_length;
|
||||
dirname_part(dir_name, file_name, &dir_name_length);
|
||||
return my_sync_dir(dir_name, my_flags);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
int my_sync_dir_by_file(const char *file_name __attribute__((unused)),
|
||||
myf my_flags __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NEED_EXPLICIT_SYNC_DIR */
|
||||
|
||||
|
||||
+216
-110
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -22,25 +22,20 @@
|
||||
#include <m_string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef THREAD
|
||||
#ifdef USE_TLS
|
||||
pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
|
||||
#else
|
||||
pthread_key(struct st_my_thread_var, THR_KEY_mysys);
|
||||
#endif /* USE_TLS */
|
||||
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
|
||||
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
|
||||
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time,
|
||||
THR_LOCK_myisam_mmap;
|
||||
mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open,
|
||||
THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_myisam, THR_LOCK_heap,
|
||||
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time,
|
||||
THR_LOCK_myisam_mmap;
|
||||
|
||||
pthread_cond_t THR_COND_threads;
|
||||
mysql_cond_t THR_COND_threads;
|
||||
uint THR_thread_count= 0;
|
||||
uint my_thread_end_wait_time= 5;
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
pthread_mutex_t LOCK_localtime_r;
|
||||
mysql_mutex_t LOCK_localtime_r;
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
pthread_mutex_t LOCK_gethostbyname_r;
|
||||
mysql_mutex_t LOCK_gethostbyname_r;
|
||||
#endif
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_t my_fast_mutexattr;
|
||||
@@ -48,7 +43,9 @@ pthread_mutexattr_t my_fast_mutexattr;
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_t my_errorcheck_mutexattr;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static void install_sigabrt_handler();
|
||||
#endif
|
||||
#ifdef TARGET_OS_LINUX
|
||||
|
||||
/*
|
||||
@@ -69,6 +66,108 @@ nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
|
||||
|
||||
static uint get_thread_lib(void);
|
||||
|
||||
/** True if @c my_thread_basic_global_init() has been called. */
|
||||
static my_bool my_thread_basic_global_init_done= 0;
|
||||
|
||||
/**
|
||||
Perform a minimal initialisation of mysys, when compiled with threads.
|
||||
The initialisation performed is sufficient to:
|
||||
- allocate memory
|
||||
- perform file operations
|
||||
- use charsets
|
||||
- use my_errno
|
||||
@sa my_basic_init
|
||||
@sa my_thread_basic_global_reinit
|
||||
*/
|
||||
my_bool my_thread_basic_global_init(void)
|
||||
{
|
||||
int pth_ret;
|
||||
|
||||
if (my_thread_basic_global_init_done)
|
||||
return 0;
|
||||
my_thread_basic_global_init_done= 1;
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "fast" a.k.a "adaptive"
|
||||
|
||||
In this case the thread may steal the mutex from some other thread
|
||||
that is waiting for the same mutex. This will save us some
|
||||
context switches but may cause a thread to 'starve forever' while
|
||||
waiting for the mutex (not likely if the code within the mutex is
|
||||
short).
|
||||
*/
|
||||
pthread_mutexattr_init(&my_fast_mutexattr);
|
||||
pthread_mutexattr_settype(&my_fast_mutexattr,
|
||||
PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
#endif
|
||||
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "errorcheck"
|
||||
*/
|
||||
pthread_mutexattr_init(&my_errorcheck_mutexattr);
|
||||
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
|
||||
PTHREAD_MUTEX_ERRORCHECK);
|
||||
#endif
|
||||
|
||||
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
|
||||
|
||||
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (my_thread_init())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Re-initialize components initialized early with @c my_thread_basic_global_init.
|
||||
Some mutexes were initialized before the instrumentation.
|
||||
Destroy + create them again, now that the instrumentation
|
||||
is in place.
|
||||
This is safe, since this function() is called before creating new threads,
|
||||
so the mutexes are not in use.
|
||||
*/
|
||||
void my_thread_basic_global_reinit(void)
|
||||
{
|
||||
struct st_my_thread_var *tmp;
|
||||
|
||||
DBUG_ASSERT(my_thread_basic_global_init_done);
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
my_init_mysys_psi_keys();
|
||||
#endif
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_malloc);
|
||||
mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_open);
|
||||
mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_charset);
|
||||
mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_mutex_destroy(&THR_LOCK_threads);
|
||||
mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST);
|
||||
|
||||
tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys);
|
||||
DBUG_ASSERT(tmp);
|
||||
|
||||
mysql_mutex_destroy(&tmp->mutex);
|
||||
mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST);
|
||||
|
||||
mysql_cond_destroy(&tmp->suspend);
|
||||
mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
initialize thread environment
|
||||
|
||||
@@ -82,14 +181,10 @@ static uint get_thread_lib(void);
|
||||
|
||||
my_bool my_thread_global_init(void)
|
||||
{
|
||||
int pth_ret;
|
||||
thd_lib_detected= get_thread_lib();
|
||||
|
||||
if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0)
|
||||
{
|
||||
fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret);
|
||||
if (my_thread_basic_global_init())
|
||||
return 1;
|
||||
}
|
||||
|
||||
thd_lib_detected= get_thread_lib();
|
||||
|
||||
#ifdef TARGET_OS_LINUX
|
||||
/*
|
||||
@@ -118,50 +213,27 @@ my_bool my_thread_global_init(void)
|
||||
}
|
||||
#endif /* TARGET_OS_LINUX */
|
||||
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "fast" a.k.a "adaptive"
|
||||
mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_isam, &THR_LOCK_isam, MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_THR_LOCK_time, &THR_LOCK_time, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
|
||||
|
||||
In this case the thread may steal the mutex from some other thread
|
||||
that is waiting for the same mutex. This will save us some
|
||||
context switches but may cause a thread to 'starve forever' while
|
||||
waiting for the mutex (not likely if the code within the mutex is
|
||||
short).
|
||||
*/
|
||||
pthread_mutexattr_init(&my_fast_mutexattr);
|
||||
pthread_mutexattr_settype(&my_fast_mutexattr,
|
||||
PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
#endif
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
/*
|
||||
Set mutex type to "errorcheck"
|
||||
*/
|
||||
pthread_mutexattr_init(&my_errorcheck_mutexattr);
|
||||
pthread_mutexattr_settype(&my_errorcheck_mutexattr,
|
||||
PTHREAD_MUTEX_ERRORCHECK);
|
||||
#endif
|
||||
|
||||
pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
|
||||
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
|
||||
pthread_mutex_init(&THR_LOCK_myisam_mmap,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
|
||||
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&THR_COND_threads, NULL);
|
||||
#if defined( __WIN__) || defined(OS2)
|
||||
win_pthread_init();
|
||||
#endif
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_LOCK_gethostbyname_r,
|
||||
&LOCK_gethostbyname_r, MY_MUTEX_INIT_SLOW);
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
install_sigabrt_handler();
|
||||
#endif
|
||||
|
||||
if (my_thread_init())
|
||||
{
|
||||
my_thread_global_end(); /* Clean up */
|
||||
@@ -177,11 +249,11 @@ void my_thread_global_end(void)
|
||||
my_bool all_threads_killed= 1;
|
||||
|
||||
set_timespec(abstime, my_thread_end_wait_time);
|
||||
pthread_mutex_lock(&THR_LOCK_threads);
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
while (THR_thread_count > 0)
|
||||
{
|
||||
int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
|
||||
&abstime);
|
||||
int error= mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
|
||||
&abstime);
|
||||
if (error == ETIMEDOUT || error == ETIME)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_KILL
|
||||
@@ -199,7 +271,7 @@ void my_thread_global_end(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&THR_LOCK_threads);
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
|
||||
pthread_key_delete(THR_KEY_mysys);
|
||||
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
|
||||
@@ -208,27 +280,29 @@ void my_thread_global_end(void)
|
||||
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
|
||||
#endif
|
||||
pthread_mutex_destroy(&THR_LOCK_malloc);
|
||||
pthread_mutex_destroy(&THR_LOCK_open);
|
||||
pthread_mutex_destroy(&THR_LOCK_lock);
|
||||
pthread_mutex_destroy(&THR_LOCK_isam);
|
||||
pthread_mutex_destroy(&THR_LOCK_myisam);
|
||||
pthread_mutex_destroy(&THR_LOCK_myisam_mmap);
|
||||
pthread_mutex_destroy(&THR_LOCK_heap);
|
||||
pthread_mutex_destroy(&THR_LOCK_net);
|
||||
pthread_mutex_destroy(&THR_LOCK_time);
|
||||
pthread_mutex_destroy(&THR_LOCK_charset);
|
||||
mysql_mutex_destroy(&THR_LOCK_malloc);
|
||||
mysql_mutex_destroy(&THR_LOCK_open);
|
||||
mysql_mutex_destroy(&THR_LOCK_lock);
|
||||
mysql_mutex_destroy(&THR_LOCK_isam);
|
||||
mysql_mutex_destroy(&THR_LOCK_myisam);
|
||||
mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
|
||||
mysql_mutex_destroy(&THR_LOCK_heap);
|
||||
mysql_mutex_destroy(&THR_LOCK_net);
|
||||
mysql_mutex_destroy(&THR_LOCK_time);
|
||||
mysql_mutex_destroy(&THR_LOCK_charset);
|
||||
if (all_threads_killed)
|
||||
{
|
||||
pthread_mutex_destroy(&THR_LOCK_threads);
|
||||
pthread_cond_destroy(&THR_COND_threads);
|
||||
mysql_mutex_destroy(&THR_LOCK_threads);
|
||||
mysql_cond_destroy(&THR_COND_threads);
|
||||
}
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
pthread_mutex_destroy(&LOCK_localtime_r);
|
||||
mysql_mutex_destroy(&LOCK_localtime_r);
|
||||
#endif
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
pthread_mutex_destroy(&LOCK_gethostbyname_r);
|
||||
mysql_mutex_destroy(&LOCK_gethostbyname_r);
|
||||
#endif
|
||||
|
||||
my_thread_basic_global_init_done= 0;
|
||||
}
|
||||
|
||||
static my_thread_id thread_id= 0;
|
||||
@@ -263,7 +337,6 @@ my_bool my_thread_init(void)
|
||||
(ulong) pthread_self());
|
||||
#endif
|
||||
|
||||
#if !defined(__WIN__) || defined(USE_TLS)
|
||||
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
|
||||
{
|
||||
#ifdef EXTRA_DEBUG_THREADS
|
||||
@@ -272,34 +345,29 @@ my_bool my_thread_init(void)
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
install_sigabrt_handler();
|
||||
#endif
|
||||
|
||||
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
pthread_setspecific(THR_KEY_mysys,tmp);
|
||||
|
||||
#else /* defined(__WIN__) && !(defined(USE_TLS) */
|
||||
/*
|
||||
Skip initialization if the thread specific variable is already initialized
|
||||
*/
|
||||
if (THR_KEY_mysys.id)
|
||||
goto end;
|
||||
tmp= &THR_KEY_mysys;
|
||||
#endif
|
||||
#if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
|
||||
tmp->pthread_self= (pthread_t) getpid();
|
||||
#else
|
||||
tmp->pthread_self= pthread_self();
|
||||
#endif
|
||||
pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&tmp->suspend, NULL);
|
||||
tmp->init= 1;
|
||||
mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL);
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_threads);
|
||||
tmp->stack_ends_here= (char*)&tmp +
|
||||
STACK_DIRECTION * (long)my_thread_stack_size;
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
tmp->id= ++thread_id;
|
||||
++THR_thread_count;
|
||||
pthread_mutex_unlock(&THR_LOCK_threads);
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
tmp->init= 1;
|
||||
#ifndef DBUG_OFF
|
||||
/* Generate unique name for thread */
|
||||
(void) my_thread_name();
|
||||
@@ -331,6 +399,17 @@ void my_thread_end(void)
|
||||
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
|
||||
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
/*
|
||||
Remove the instrumentation for this thread.
|
||||
This must be done before trashing st_my_thread_var,
|
||||
because the LF_HASH depends on it.
|
||||
*/
|
||||
if (PSI_server)
|
||||
PSI_server->delete_current_thread();
|
||||
#endif
|
||||
|
||||
if (tmp && tmp->init)
|
||||
{
|
||||
#if !defined(DBUG_OFF)
|
||||
@@ -344,14 +423,10 @@ void my_thread_end(void)
|
||||
#endif
|
||||
#if !defined(__bsdi__) && !defined(__OpenBSD__)
|
||||
/* bsdi and openbsd 3.5 dumps core here */
|
||||
pthread_cond_destroy(&tmp->suspend);
|
||||
mysql_cond_destroy(&tmp->suspend);
|
||||
#endif
|
||||
pthread_mutex_destroy(&tmp->mutex);
|
||||
#if !defined(__WIN__) || defined(USE_TLS)
|
||||
mysql_mutex_destroy(&tmp->mutex);
|
||||
free(tmp);
|
||||
#else
|
||||
tmp->init= 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
Decrement counter for number of running threads. We are using this
|
||||
@@ -359,16 +434,13 @@ void my_thread_end(void)
|
||||
my_thread_end and thus freed all memory they have allocated in
|
||||
my_thread_init() and DBUG_xxxx
|
||||
*/
|
||||
pthread_mutex_lock(&THR_LOCK_threads);
|
||||
mysql_mutex_lock(&THR_LOCK_threads);
|
||||
DBUG_ASSERT(THR_thread_count != 0);
|
||||
if (--THR_thread_count == 0)
|
||||
pthread_cond_signal(&THR_COND_threads);
|
||||
pthread_mutex_unlock(&THR_LOCK_threads);
|
||||
mysql_cond_signal(&THR_COND_threads);
|
||||
mysql_mutex_unlock(&THR_LOCK_threads);
|
||||
}
|
||||
/* The following free has to be done, even if my_thread_var() is 0 */
|
||||
#if !defined(__WIN__) || defined(USE_TLS)
|
||||
pthread_setspecific(THR_KEY_mysys,0);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct st_my_thread_var *_my_thread_var(void)
|
||||
@@ -406,6 +478,15 @@ const char *my_thread_name(void)
|
||||
}
|
||||
return tmp->name;
|
||||
}
|
||||
|
||||
/* Return pointer to DBUG for holding current state */
|
||||
|
||||
extern void **my_thread_var_dbug()
|
||||
{
|
||||
struct st_my_thread_var *tmp=
|
||||
my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
|
||||
return tmp && tmp->init ? &tmp->dbug : 0;
|
||||
}
|
||||
#endif /* DBUG_OFF */
|
||||
|
||||
|
||||
@@ -424,4 +505,29 @@ static uint get_thread_lib(void)
|
||||
return THD_LIB_OTHER;
|
||||
}
|
||||
|
||||
#endif /* THREAD */
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
In Visual Studio 2005 and later, default SIGABRT handler will overwrite
|
||||
any unhandled exception filter set by the application and will try to
|
||||
call JIT debugger. This is not what we want, this we calling __debugbreak
|
||||
to stop in debugger, if process is being debugged or to generate
|
||||
EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
|
||||
*/
|
||||
|
||||
#if (_MSC_VER >= 1400)
|
||||
static void my_sigabrt_handler(int sig)
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
#endif /*_MSC_VER >=1400 */
|
||||
|
||||
static void install_sigabrt_handler(void)
|
||||
{
|
||||
#if (_MSC_VER >=1400)
|
||||
/*abort() should not override our exception filter*/
|
||||
_set_abort_behavior(0,_CALL_REPORTFAULT);
|
||||
signal(SIGABRT,my_sigabrt_handler);
|
||||
#endif /* _MSC_VER >=1400 */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,16 +16,116 @@
|
||||
/*****************************************************************************
|
||||
** The following is a simple implementation of posix conditions
|
||||
*****************************************************************************/
|
||||
#if defined(_WIN32)
|
||||
|
||||
#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
|
||||
#include "mysys_priv.h"
|
||||
#if defined(THREAD) && defined(__WIN__)
|
||||
#include <m_string.h>
|
||||
#undef getpid
|
||||
#include <process.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
|
||||
/*
|
||||
Windows native condition variables. We use runtime loading / function
|
||||
pointers, because they are not available on XP
|
||||
*/
|
||||
|
||||
/* Prototypes and function pointers for condition variable functions */
|
||||
typedef VOID (WINAPI * InitializeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef BOOL (WINAPI * SleepConditionVariableCSProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable,
|
||||
PCRITICAL_SECTION CriticalSection,
|
||||
DWORD dwMilliseconds);
|
||||
|
||||
typedef VOID (WINAPI * WakeAllConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef VOID (WINAPI * WakeConditionVariableProc)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
static InitializeConditionVariableProc my_InitializeConditionVariable;
|
||||
static SleepConditionVariableCSProc my_SleepConditionVariableCS;
|
||||
static WakeAllConditionVariableProc my_WakeAllConditionVariable;
|
||||
static WakeConditionVariableProc my_WakeConditionVariable;
|
||||
|
||||
|
||||
/**
|
||||
Indicates if we have native condition variables,
|
||||
initialized first time pthread_cond_init is called.
|
||||
*/
|
||||
|
||||
static BOOL have_native_conditions= FALSE;
|
||||
|
||||
|
||||
/**
|
||||
Check if native conditions can be used, load function pointers
|
||||
*/
|
||||
|
||||
static void check_native_cond_availability(void)
|
||||
{
|
||||
HMODULE module= GetModuleHandle("kernel32");
|
||||
|
||||
my_InitializeConditionVariable= (InitializeConditionVariableProc)
|
||||
GetProcAddress(module, "InitializeConditionVariable");
|
||||
my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
|
||||
GetProcAddress(module, "SleepConditionVariableCS");
|
||||
my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
|
||||
GetProcAddress(module, "WakeAllConditionVariable");
|
||||
my_WakeConditionVariable= (WakeConditionVariableProc)
|
||||
GetProcAddress(module, "WakeConditionVariable");
|
||||
|
||||
if (my_InitializeConditionVariable)
|
||||
have_native_conditions= TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convert abstime to milliseconds
|
||||
*/
|
||||
|
||||
static DWORD get_milliseconds(const struct timespec *abstime)
|
||||
{
|
||||
long long millis;
|
||||
union ft64 now;
|
||||
|
||||
if (abstime == NULL)
|
||||
return INFINITE;
|
||||
|
||||
GetSystemTimeAsFileTime(&now.ft);
|
||||
|
||||
/*
|
||||
Calculate time left to abstime
|
||||
- subtract start time from current time(values are in 100ns units)
|
||||
- convert to millisec by dividing with 10000
|
||||
*/
|
||||
millis= (abstime->tv.i64 - now.i64) / 10000;
|
||||
|
||||
/* Don't allow the timeout to be negative */
|
||||
if (millis < 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
Make sure the calculated timeout does not exceed original timeout
|
||||
value which could cause "wait for ever" if system time changes
|
||||
*/
|
||||
if (millis > abstime->max_timeout_msec)
|
||||
millis= abstime->max_timeout_msec;
|
||||
|
||||
if (millis > UINT_MAX)
|
||||
millis= UINT_MAX;
|
||||
|
||||
return (DWORD)millis;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Old (pre-vista) implementation using events
|
||||
*/
|
||||
|
||||
static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
{
|
||||
cond->waiting= 0;
|
||||
InitializeCriticalSection(&cond->lock_waiting);
|
||||
@@ -54,7 +154,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
|
||||
static int legacy_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
DeleteCriticalSection(&cond->lock_waiting);
|
||||
|
||||
@@ -66,48 +167,13 @@ int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_timedwait(cond,mutex,NULL);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
int result;
|
||||
long timeout;
|
||||
union ft64 now;
|
||||
|
||||
if( abstime != NULL )
|
||||
{
|
||||
GetSystemTimeAsFileTime(&now.ft);
|
||||
|
||||
/*
|
||||
Calculate time left to abstime
|
||||
- subtract start time from current time(values are in 100ns units)
|
||||
- convert to millisec by dividing with 10000
|
||||
*/
|
||||
timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
|
||||
|
||||
/* Don't allow the timeout to be negative */
|
||||
if (timeout < 0)
|
||||
timeout= 0L;
|
||||
|
||||
/*
|
||||
Make sure the calucated timeout does not exceed original timeout
|
||||
value which could cause "wait for ever" if system time changes
|
||||
*/
|
||||
if (timeout > abstime->max_timeout_msec)
|
||||
timeout= abstime->max_timeout_msec;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No time specified; don't expire */
|
||||
timeout= INFINITE;
|
||||
}
|
||||
DWORD timeout;
|
||||
|
||||
timeout= get_milliseconds(abstime);
|
||||
/*
|
||||
Block access if previous broadcast hasn't finished.
|
||||
This is just for safety and should normally not
|
||||
@@ -143,7 +209,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
static int legacy_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
|
||||
@@ -156,7 +222,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
static int legacy_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->lock_waiting);
|
||||
/*
|
||||
@@ -178,11 +244,91 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Posix API functions. Just choose between native and legacy implementation.
|
||||
*/
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
||||
{
|
||||
/*
|
||||
Once initialization is used here rather than in my_init(), to
|
||||
1) avoid my_init() pitfalls- undefined order in which initialization should
|
||||
run
|
||||
2) be potentially useful C++ (in static constructors that run before main())
|
||||
3) just to simplify the API.
|
||||
Also, the overhead of my_pthread_once is very small.
|
||||
*/
|
||||
static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
|
||||
my_pthread_once(&once_control, check_native_cond_availability);
|
||||
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_InitializeConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_init(cond, attr);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
return 0; /* no destroy function */
|
||||
else
|
||||
return legacy_cond_destroy(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_WakeAllConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_broadcast(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
my_WakeConditionVariable(&cond->native_cond);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_signal(cond);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
struct timespec *abstime)
|
||||
{
|
||||
if (have_native_conditions)
|
||||
{
|
||||
DWORD timeout= get_milliseconds(abstime);
|
||||
if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
|
||||
return ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return legacy_cond_timedwait(cond, mutex, abstime);
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_timedwait(cond, mutex, NULL);
|
||||
}
|
||||
|
||||
|
||||
int pthread_attr_init(pthread_attr_t *connect_att)
|
||||
{
|
||||
connect_att->dwStackSize = 0;
|
||||
connect_att->dwCreatingFlag = 0;
|
||||
connect_att->priority = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -192,12 +338,6 @@ int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_attr_setprio(pthread_attr_t *connect_att,int priority)
|
||||
{
|
||||
connect_att->priority=priority;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_attr_destroy(pthread_attr_t *connect_att)
|
||||
{
|
||||
bzero((uchar*) connect_att,sizeof(*connect_att));
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/* Copyright (C) 2000-2005 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "m_string.h"
|
||||
#ifdef __WIN__
|
||||
|
||||
/* Windows NT/2000 discretionary access control utility functions. */
|
||||
|
||||
/*
|
||||
Check if the operating system is built on NT technology.
|
||||
|
||||
RETURN
|
||||
0 Windows 95/98/Me
|
||||
1 otherwise
|
||||
*/
|
||||
|
||||
static my_bool is_nt()
|
||||
{
|
||||
return GetVersion() < 0x80000000;
|
||||
}
|
||||
|
||||
/*
|
||||
Auxilary structure to store pointers to the data which we need to keep
|
||||
around while SECURITY_ATTRIBUTES is in use.
|
||||
*/
|
||||
|
||||
typedef struct st_my_security_attr
|
||||
{
|
||||
PSID everyone_sid;
|
||||
PACL dacl;
|
||||
} My_security_attr;
|
||||
|
||||
|
||||
/*
|
||||
Allocate and initialize SECURITY_ATTRIBUTES setting up access
|
||||
rights for the owner and group `Everybody'.
|
||||
|
||||
SYNOPSIS
|
||||
my_security_attr_create()
|
||||
psa [OUT] pointer to store the pointer to SA in
|
||||
perror [OUT] pointer to store error message if there was an
|
||||
error
|
||||
owner_rights [IN] access rights for the owner
|
||||
everyone_rights [IN] access rights for group Everybody
|
||||
|
||||
DESCRIPTION
|
||||
Set up the security attributes to provide clients with sufficient
|
||||
access rights to a kernel object. We need this function
|
||||
because if we simply grant all access to everybody (by installing
|
||||
a NULL DACL) a mailicious user can attempt a denial of service
|
||||
attack by taking ownership over the kernel object. Upon successful
|
||||
return `psa' contains a pointer to SECUIRITY_ATTRIBUTES that can be used
|
||||
to create kernel objects with proper access rights.
|
||||
|
||||
RETURN
|
||||
0 success, psa is 0 or points to a valid SA structure,
|
||||
perror is left intact
|
||||
!0 error, SA is set to 0, error message is stored in perror
|
||||
*/
|
||||
|
||||
int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror,
|
||||
DWORD owner_rights, DWORD everyone_rights)
|
||||
{
|
||||
/* Top-level SID authority */
|
||||
SID_IDENTIFIER_AUTHORITY world_auth= SECURITY_WORLD_SID_AUTHORITY;
|
||||
PSID everyone_sid= 0;
|
||||
HANDLE htoken= 0;
|
||||
SECURITY_ATTRIBUTES *sa= 0;
|
||||
PACL dacl= 0;
|
||||
DWORD owner_token_length, dacl_length;
|
||||
SECURITY_DESCRIPTOR *sd;
|
||||
PTOKEN_USER owner_token;
|
||||
PSID owner_sid;
|
||||
My_security_attr *attr;
|
||||
|
||||
if (! is_nt())
|
||||
{
|
||||
*psa= 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Get SID of Everyone group. Easier to retrieve all SIDs each time
|
||||
this function is called than worry about thread safety.
|
||||
*/
|
||||
if (! AllocateAndInitializeSid(&world_auth, 1, SECURITY_WORLD_RID,
|
||||
0, 0, 0, 0, 0, 0, 0, &everyone_sid))
|
||||
{
|
||||
*perror= "Failed to retrieve the SID of Everyone group";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
Get SID of the owner. Using GetSecurityInfo this task can be done
|
||||
in just one call instead of five, but GetSecurityInfo declared in
|
||||
aclapi.h, so I hesitate to use it.
|
||||
SIC: OpenThreadToken works only if there is an active impersonation
|
||||
token, hence OpenProcessToken is used.
|
||||
*/
|
||||
if (! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken))
|
||||
{
|
||||
*perror= "Failed to retrieve thread access token";
|
||||
goto error;
|
||||
}
|
||||
GetTokenInformation(htoken, TokenUser, 0, 0, &owner_token_length);
|
||||
|
||||
if (! my_multi_malloc(MYF(MY_WME),
|
||||
&sa, ALIGN_SIZE(sizeof(SECURITY_ATTRIBUTES)) +
|
||||
sizeof(My_security_attr),
|
||||
&sd, sizeof(SECURITY_DESCRIPTOR),
|
||||
&owner_token, owner_token_length,
|
||||
0))
|
||||
{
|
||||
*perror= "Failed to allocate memory for SECURITY_ATTRIBUTES";
|
||||
goto error;
|
||||
}
|
||||
bzero(owner_token, owner_token_length);
|
||||
if (! GetTokenInformation(htoken, TokenUser, owner_token,
|
||||
owner_token_length, &owner_token_length))
|
||||
{
|
||||
*perror= "GetTokenInformation failed";
|
||||
goto error;
|
||||
}
|
||||
owner_sid= owner_token->User.Sid;
|
||||
|
||||
if (! IsValidSid(owner_sid))
|
||||
{
|
||||
*perror= "IsValidSid failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Calculate the amount of memory that must be allocated for the DACL */
|
||||
dacl_length= sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)) * 2 +
|
||||
GetLengthSid(everyone_sid) + GetLengthSid(owner_sid);
|
||||
|
||||
/* Create an ACL */
|
||||
if (! (dacl= (PACL) my_malloc(dacl_length, MYF(MY_ZEROFILL|MY_WME))))
|
||||
{
|
||||
*perror= "Failed to allocate memory for DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! InitializeAcl(dacl, dacl_length, ACL_REVISION))
|
||||
{
|
||||
*perror= "Failed to initialize DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! AddAccessAllowedAce(dacl, ACL_REVISION, everyone_rights, everyone_sid))
|
||||
{
|
||||
*perror= "Failed to set up DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! AddAccessAllowedAce(dacl, ACL_REVISION, owner_rights, owner_sid))
|
||||
{
|
||||
*perror= "Failed to set up DACL";
|
||||
goto error;
|
||||
}
|
||||
if (! InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))
|
||||
{
|
||||
*perror= "Could not initialize security descriptor";
|
||||
goto error;
|
||||
}
|
||||
if (! SetSecurityDescriptorDacl(sd, TRUE, dacl, FALSE))
|
||||
{
|
||||
*perror= "Failed to install DACL";
|
||||
goto error;
|
||||
}
|
||||
|
||||
sa->nLength= sizeof(*sa);
|
||||
sa->bInheritHandle= TRUE;
|
||||
sa->lpSecurityDescriptor= sd;
|
||||
/* Save pointers to everyone_sid and dacl to be able to clean them up */
|
||||
attr= (My_security_attr*) (((char*) sa) + ALIGN_SIZE(sizeof(*sa)));
|
||||
attr->everyone_sid= everyone_sid;
|
||||
attr->dacl= dacl;
|
||||
*psa= sa;
|
||||
|
||||
CloseHandle(htoken);
|
||||
return 0;
|
||||
error:
|
||||
if (everyone_sid)
|
||||
FreeSid(everyone_sid);
|
||||
if (htoken)
|
||||
CloseHandle(htoken);
|
||||
my_free(sa);
|
||||
my_free(dacl);
|
||||
*psa= 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup security attributes freeing used memory.
|
||||
|
||||
SYNOPSIS
|
||||
my_security_attr_free()
|
||||
sa security attributes
|
||||
*/
|
||||
|
||||
void my_security_attr_free(SECURITY_ATTRIBUTES *sa)
|
||||
{
|
||||
if (sa)
|
||||
{
|
||||
My_security_attr *attr= (My_security_attr*)
|
||||
(((char*)sa) + ALIGN_SIZE(sizeof(*sa)));
|
||||
FreeSid(attr->everyone_sid);
|
||||
my_free(attr->dacl);
|
||||
my_free(sa);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __WIN__ */
|
||||
@@ -0,0 +1,123 @@
|
||||
/* Copyright (C) 2008 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Convert Windows API error (GetLastError() to Posix equivalent (errno)
|
||||
The exported function my_osmaperr() is modelled after and borrows
|
||||
heavily from undocumented _dosmaperr()(found of the static Microsoft C runtime).
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
|
||||
struct errentry
|
||||
{
|
||||
unsigned long oscode; /* OS return value */
|
||||
int sysv_errno; /* System V error code */
|
||||
};
|
||||
|
||||
static struct errentry errtable[]= {
|
||||
{ ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
|
||||
{ ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
|
||||
{ ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
|
||||
{ ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
|
||||
{ ERROR_ACCESS_DENIED, EACCES }, /* 5 */
|
||||
{ ERROR_INVALID_HANDLE, EBADF }, /* 6 */
|
||||
{ ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
|
||||
{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
|
||||
{ ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
|
||||
{ ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
|
||||
{ ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
|
||||
{ ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
|
||||
{ ERROR_INVALID_DATA, EINVAL }, /* 13 */
|
||||
{ ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
|
||||
{ ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
|
||||
{ ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
|
||||
{ ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
|
||||
{ ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
|
||||
{ ERROR_BAD_NETPATH, ENOENT }, /* 53 */
|
||||
{ ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
|
||||
{ ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
|
||||
{ ERROR_FILE_EXISTS, EEXIST }, /* 80 */
|
||||
{ ERROR_CANNOT_MAKE, EACCES }, /* 82 */
|
||||
{ ERROR_FAIL_I24, EACCES }, /* 83 */
|
||||
{ ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
|
||||
{ ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
|
||||
{ ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
|
||||
{ ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
|
||||
{ ERROR_DISK_FULL, ENOSPC }, /* 112 */
|
||||
{ ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
|
||||
{ ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
|
||||
{ ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
|
||||
{ ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
|
||||
{ ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
|
||||
{ ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
|
||||
{ ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
|
||||
{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
|
||||
{ ERROR_NOT_LOCKED, EACCES }, /* 158 */
|
||||
{ ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
|
||||
{ ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
|
||||
{ ERROR_LOCK_FAILED, EACCES }, /* 167 */
|
||||
{ ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
|
||||
{ ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
|
||||
{ ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
|
||||
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
|
||||
};
|
||||
|
||||
/* size of the table */
|
||||
#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
|
||||
|
||||
/* The following two constants must be the minimum and maximum
|
||||
values in the (contiguous) range of Exec Failure errors. */
|
||||
#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
|
||||
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
|
||||
|
||||
/* These are the low and high value in the range of errors that are
|
||||
access violations */
|
||||
#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
|
||||
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
|
||||
|
||||
|
||||
static int get_errno_from_oserr(unsigned long oserrno)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check the table for the OS error code */
|
||||
for (i= 0; i < ERRTABLESIZE; ++i)
|
||||
{
|
||||
if (oserrno == errtable[i].oscode)
|
||||
{
|
||||
return errtable[i].sysv_errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* The error code wasn't in the table. We check for a range of */
|
||||
/* EACCES errors or exec failure errors (ENOEXEC). Otherwise */
|
||||
/* EINVAL is returned. */
|
||||
|
||||
if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
|
||||
return EACCES;
|
||||
else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
|
||||
return ENOEXEC;
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Set errno corresponsing to GetLastError() value */
|
||||
void my_osmaperr ( unsigned long oserrno)
|
||||
{
|
||||
errno= get_errno_from_oserr(oserrno);
|
||||
}
|
||||
@@ -0,0 +1,681 @@
|
||||
/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
The purpose of this file is to provide implementation of file IO routines on
|
||||
Windows that can be thought as drop-in replacement for corresponding C runtime
|
||||
functionality.
|
||||
|
||||
Compared to Windows CRT, this one
|
||||
- does not have the same file descriptor
|
||||
limitation (default is 16384 and can be increased further, whereas CRT poses
|
||||
a hard limit of 2048 file descriptors)
|
||||
- the file operations are not serialized
|
||||
- positional IO pread/pwrite is ported here.
|
||||
- no text mode for files, all IO is "binary"
|
||||
|
||||
Naming convention:
|
||||
All routines are prefixed with my_win_, e.g Posix open() is implemented with
|
||||
my_win_open()
|
||||
|
||||
Implemented are
|
||||
- POSIX routines(e.g open, read, lseek ...)
|
||||
- Some ANSI C stream routines (fopen, fdopen, fileno, fclose)
|
||||
- Windows CRT equvalients (my_get_osfhandle, open_osfhandle)
|
||||
|
||||
Worth to note:
|
||||
- File descriptors used here are located in a range that is not compatible
|
||||
with CRT on purpose. Attempt to use a file descriptor from Windows CRT library
|
||||
range in my_win_* function will be punished with DBUG_ASSERT()
|
||||
|
||||
- File streams (FILE *) are actually from the C runtime. The routines provided
|
||||
here are useful only in scernarios that use low-level IO with my_win_fileno()
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <share.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Associates a file descriptor with an existing operating-system file handle.*/
|
||||
File my_open_osfhandle(HANDLE handle, int oflag)
|
||||
{
|
||||
int offset= -1;
|
||||
uint i;
|
||||
DBUG_ENTER("my_open_osfhandle");
|
||||
|
||||
mysql_mutex_lock(&THR_LOCK_open);
|
||||
for(i= MY_FILE_MIN; i < my_file_limit;i++)
|
||||
{
|
||||
if(my_file_info[i].fhandle == 0)
|
||||
{
|
||||
struct st_my_file_info *finfo= &(my_file_info[i]);
|
||||
finfo->type= FILE_BY_OPEN;
|
||||
finfo->fhandle= handle;
|
||||
finfo->oflag= oflag;
|
||||
offset= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&THR_LOCK_open);
|
||||
if(offset == -1)
|
||||
errno= EMFILE; /* to many file handles open */
|
||||
DBUG_RETURN(offset);
|
||||
}
|
||||
|
||||
|
||||
static void invalidate_fd(File fd)
|
||||
{
|
||||
DBUG_ENTER("invalidate_fd");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
my_file_info[fd].fhandle= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Get Windows handle for a file descriptor */
|
||||
HANDLE my_get_osfhandle(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_get_osfhandle");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
DBUG_RETURN(my_file_info[fd].fhandle);
|
||||
}
|
||||
|
||||
|
||||
static int my_get_open_flags(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_get_open_flags");
|
||||
DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
|
||||
DBUG_RETURN(my_file_info[fd].oflag);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open a file with sharing. Similar to _sopen() from libc, but allows managing
|
||||
share delete on win32
|
||||
|
||||
SYNOPSIS
|
||||
my_win_sopen()
|
||||
path file name
|
||||
oflag operation flags
|
||||
shflag share flag
|
||||
pmode permission flags
|
||||
|
||||
RETURN VALUE
|
||||
File descriptor of opened file if success
|
||||
-1 and sets errno if fails.
|
||||
*/
|
||||
|
||||
File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
|
||||
{
|
||||
int fh; /* handle of opened file */
|
||||
int mask;
|
||||
HANDLE osfh; /* OS handle of opened file */
|
||||
DWORD fileaccess; /* OS file access (requested) */
|
||||
DWORD fileshare; /* OS file sharing mode */
|
||||
DWORD filecreate; /* OS method of opening/creating */
|
||||
DWORD fileattrib; /* OS file attribute flags */
|
||||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||||
|
||||
DBUG_ENTER("my_win_sopen");
|
||||
|
||||
if (check_if_legal_filename(path))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
SecurityAttributes.nLength= sizeof(SecurityAttributes);
|
||||
SecurityAttributes.lpSecurityDescriptor= NULL;
|
||||
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
|
||||
|
||||
/* decode the access flags */
|
||||
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY: /* read access */
|
||||
fileaccess= GENERIC_READ;
|
||||
break;
|
||||
case _O_WRONLY: /* write access */
|
||||
fileaccess= GENERIC_WRITE;
|
||||
break;
|
||||
case _O_RDWR: /* read and write access */
|
||||
fileaccess= GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default: /* error, bad oflag */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode sharing flags */
|
||||
switch (shflag) {
|
||||
case _SH_DENYRW: /* exclusive access except delete */
|
||||
fileshare= FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYWR: /* share read and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRD: /* share write and delete access */
|
||||
fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYNO: /* share read, write and delete access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _SH_DENYRWD: /* exclusive access */
|
||||
fileshare= 0L;
|
||||
break;
|
||||
case _SH_DENYWRD: /* share read access */
|
||||
fileshare= FILE_SHARE_READ;
|
||||
break;
|
||||
case _SH_DENYRDD: /* share write access */
|
||||
fileshare= FILE_SHARE_WRITE;
|
||||
break;
|
||||
case _SH_DENYDEL: /* share read and write access */
|
||||
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
break;
|
||||
default: /* error, bad shflag */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode open/create method flags */
|
||||
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
|
||||
case 0:
|
||||
case _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= OPEN_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT:
|
||||
filecreate= OPEN_ALWAYS;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_EXCL:
|
||||
case _O_CREAT | _O_TRUNC | _O_EXCL:
|
||||
filecreate= CREATE_NEW;
|
||||
break;
|
||||
|
||||
case _O_TRUNC:
|
||||
case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
|
||||
filecreate= TRUNCATE_EXISTING;
|
||||
break;
|
||||
|
||||
case _O_CREAT | _O_TRUNC:
|
||||
filecreate= CREATE_ALWAYS;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this can't happen ... all cases are covered */
|
||||
errno= EINVAL;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
/* decode file attribute flags if _O_CREAT was specified */
|
||||
fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
|
||||
if (oflag & _O_CREAT)
|
||||
{
|
||||
_umask((mask= _umask(0)));
|
||||
|
||||
if (!((pmode & ~mask) & _S_IWRITE))
|
||||
fileattrib= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
/* Set temporary file (delete-on-close) attribute if requested. */
|
||||
if (oflag & _O_TEMPORARY)
|
||||
{
|
||||
fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
fileaccess|= DELETE;
|
||||
}
|
||||
|
||||
/* Set temporary file (delay-flush-to-disk) attribute if requested.*/
|
||||
if (oflag & _O_SHORT_LIVED)
|
||||
fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
|
||||
|
||||
/* Set sequential or random access attribute if requested. */
|
||||
if (oflag & _O_SEQUENTIAL)
|
||||
fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
else if (oflag & _O_RANDOM)
|
||||
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
|
||||
|
||||
/* try to open/create the file */
|
||||
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
|
||||
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/*
|
||||
OS call to open/create file failed! map the error, release
|
||||
the lock, and return -1. note that it's not necessary to
|
||||
call _free_osfhnd (it hasn't been used yet).
|
||||
*/
|
||||
my_osmaperr(GetLastError()); /* map error */
|
||||
DBUG_RETURN(-1); /* return error to caller */
|
||||
}
|
||||
|
||||
if ((fh= my_open_osfhandle(osfh,
|
||||
oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
}
|
||||
|
||||
DBUG_RETURN(fh); /* return handle */
|
||||
}
|
||||
|
||||
|
||||
File my_win_open(const char *path, int flags)
|
||||
{
|
||||
DBUG_ENTER("my_win_open");
|
||||
DBUG_RETURN(my_win_sopen((char *) path, flags | _O_BINARY, _SH_DENYNO,
|
||||
_S_IREAD | S_IWRITE));
|
||||
}
|
||||
|
||||
|
||||
int my_win_close(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_win_close");
|
||||
if(CloseHandle(my_get_osfhandle(fd)))
|
||||
{
|
||||
invalidate_fd(fd);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset)
|
||||
{
|
||||
DWORD nBytesRead;
|
||||
HANDLE hFile;
|
||||
OVERLAPPED ov= {0};
|
||||
LARGE_INTEGER li;
|
||||
|
||||
DBUG_ENTER("my_win_pread");
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
li.QuadPart= offset;
|
||||
ov.Offset= li.LowPart;
|
||||
ov.OffsetHigh= li.HighPart;
|
||||
|
||||
if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov))
|
||||
{
|
||||
DWORD lastError= GetLastError();
|
||||
/*
|
||||
ERROR_BROKEN_PIPE is returned when no more data coming
|
||||
through e.g. a command pipe in windows : see MSDN on ReadFile.
|
||||
*/
|
||||
if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
|
||||
DBUG_RETURN(0); /*return 0 at EOF*/
|
||||
my_osmaperr(lastError);
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nBytesRead);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_read(File Filedes, uchar *Buffer, size_t Count)
|
||||
{
|
||||
DWORD nBytesRead;
|
||||
HANDLE hFile;
|
||||
|
||||
DBUG_ENTER("my_win_read");
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
|
||||
if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL))
|
||||
{
|
||||
DWORD lastError= GetLastError();
|
||||
/*
|
||||
ERROR_BROKEN_PIPE is returned when no more data coming
|
||||
through e.g. a command pipe in windows : see MSDN on ReadFile.
|
||||
*/
|
||||
if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
|
||||
DBUG_RETURN(0); /*return 0 at EOF*/
|
||||
my_osmaperr(lastError);
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nBytesRead);
|
||||
}
|
||||
|
||||
|
||||
size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count,
|
||||
my_off_t offset)
|
||||
{
|
||||
DWORD nBytesWritten;
|
||||
HANDLE hFile;
|
||||
OVERLAPPED ov= {0};
|
||||
LARGE_INTEGER li;
|
||||
|
||||
DBUG_ENTER("my_win_pwrite");
|
||||
DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu",
|
||||
Filedes, Buffer, (ulonglong)Count, (ulonglong)offset));
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
hFile= (HANDLE)my_get_osfhandle(Filedes);
|
||||
li.QuadPart= offset;
|
||||
ov.Offset= li.LowPart;
|
||||
ov.OffsetHigh= li.HighPart;
|
||||
|
||||
if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
else
|
||||
DBUG_RETURN(nBytesWritten);
|
||||
}
|
||||
|
||||
|
||||
my_off_t my_win_lseek(File fd, my_off_t pos, int whence)
|
||||
{
|
||||
LARGE_INTEGER offset;
|
||||
LARGE_INTEGER newpos;
|
||||
|
||||
DBUG_ENTER("my_win_lseek");
|
||||
|
||||
/* Check compatibility of Windows and Posix seek constants */
|
||||
compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR
|
||||
&& FILE_END == SEEK_END);
|
||||
|
||||
offset.QuadPart= pos;
|
||||
if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
newpos.QuadPart= -1;
|
||||
}
|
||||
DBUG_RETURN(newpos.QuadPart);
|
||||
}
|
||||
|
||||
|
||||
#ifndef FILE_WRITE_TO_END_OF_FILE
|
||||
#define FILE_WRITE_TO_END_OF_FILE 0xffffffff
|
||||
#endif
|
||||
size_t my_win_write(File fd, const uchar *Buffer, size_t Count)
|
||||
{
|
||||
DWORD nWritten;
|
||||
OVERLAPPED ov;
|
||||
OVERLAPPED *pov= NULL;
|
||||
HANDLE hFile;
|
||||
|
||||
DBUG_ENTER("my_win_write");
|
||||
DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %llu", fd, Buffer,
|
||||
(ulonglong)Count));
|
||||
|
||||
if(!Count)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
#ifdef _WIN64
|
||||
if(Count > UINT_MAX)
|
||||
Count= UINT_MAX;
|
||||
#endif
|
||||
|
||||
if(my_get_open_flags(fd) & _O_APPEND)
|
||||
{
|
||||
/*
|
||||
Atomic append to the end of file is is done by special initialization of
|
||||
the OVERLAPPED structure. See MSDN WriteFile documentation for more info.
|
||||
*/
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
ov.Offset= FILE_WRITE_TO_END_OF_FILE;
|
||||
ov.OffsetHigh= -1;
|
||||
pov= &ov;
|
||||
}
|
||||
|
||||
hFile= my_get_osfhandle(fd);
|
||||
if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN((size_t)-1);
|
||||
}
|
||||
DBUG_RETURN(nWritten);
|
||||
}
|
||||
|
||||
|
||||
int my_win_chsize(File fd, my_off_t newlength)
|
||||
{
|
||||
HANDLE hFile;
|
||||
LARGE_INTEGER length;
|
||||
DBUG_ENTER("my_win_chsize");
|
||||
|
||||
hFile= (HANDLE) my_get_osfhandle(fd);
|
||||
length.QuadPart= newlength;
|
||||
if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN))
|
||||
goto err;
|
||||
if (!SetEndOfFile(hFile))
|
||||
goto err;
|
||||
DBUG_RETURN(0);
|
||||
err:
|
||||
my_osmaperr(GetLastError());
|
||||
my_errno= errno;
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Get the file descriptor for stdin,stdout or stderr */
|
||||
static File my_get_stdfile_descriptor(FILE *stream)
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD nStdHandle;
|
||||
DBUG_ENTER("my_get_stdfile_descriptor");
|
||||
|
||||
if(stream == stdin)
|
||||
nStdHandle= STD_INPUT_HANDLE;
|
||||
else if(stream == stdout)
|
||||
nStdHandle= STD_OUTPUT_HANDLE;
|
||||
else if(stream == stderr)
|
||||
nStdHandle= STD_ERROR_HANDLE;
|
||||
else
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
hFile= GetStdHandle(nStdHandle);
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
DBUG_RETURN(my_open_osfhandle(hFile, 0));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
File my_win_fileno(FILE *file)
|
||||
{
|
||||
HANDLE hFile= (HANDLE)_get_osfhandle(fileno(file));
|
||||
int retval= -1;
|
||||
uint i;
|
||||
|
||||
DBUG_ENTER("my_win_fileno");
|
||||
|
||||
for(i= MY_FILE_MIN; i < my_file_limit; i++)
|
||||
{
|
||||
if(my_file_info[i].fhandle == hFile)
|
||||
{
|
||||
retval= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(retval == -1)
|
||||
/* try std stream */
|
||||
DBUG_RETURN(my_get_stdfile_descriptor(file));
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
FILE *my_win_fopen(const char *filename, const char *type)
|
||||
{
|
||||
FILE *file;
|
||||
int flags= 0;
|
||||
DBUG_ENTER("my_win_open");
|
||||
|
||||
/*
|
||||
If we are not creating, then we need to use my_access to make sure
|
||||
the file exists since Windows doesn't handle files like "com1.sym"
|
||||
very well
|
||||
*/
|
||||
if (check_if_legal_filename(filename))
|
||||
{
|
||||
errno= EACCES;
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
file= fopen(filename, type);
|
||||
if(!file)
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
if(strchr(type,'a') != NULL)
|
||||
flags= O_APPEND;
|
||||
|
||||
/*
|
||||
Register file handle in my_table_info.
|
||||
Necessary for my_fileno()
|
||||
*/
|
||||
if(my_open_osfhandle((HANDLE)_get_osfhandle(fileno(file)), flags) < 0)
|
||||
{
|
||||
fclose(file);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
|
||||
|
||||
FILE * my_win_fdopen(File fd, const char *type)
|
||||
{
|
||||
FILE *file;
|
||||
int crt_fd;
|
||||
int flags= 0;
|
||||
|
||||
DBUG_ENTER("my_win_fdopen");
|
||||
|
||||
if(strchr(type,'a') != NULL)
|
||||
flags= O_APPEND;
|
||||
/* Convert OS file handle to CRT file descriptor and then call fdopen*/
|
||||
crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags);
|
||||
if(crt_fd < 0)
|
||||
file= NULL;
|
||||
else
|
||||
file= fdopen(crt_fd, type);
|
||||
DBUG_RETURN(file);
|
||||
}
|
||||
|
||||
|
||||
int my_win_fclose(FILE *file)
|
||||
{
|
||||
File fd;
|
||||
|
||||
DBUG_ENTER("my_win_close");
|
||||
fd= my_fileno(file);
|
||||
if(fd < 0)
|
||||
DBUG_RETURN(-1);
|
||||
if(fclose(file) < 0)
|
||||
DBUG_RETURN(-1);
|
||||
invalidate_fd(fd);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Quick and dirty my_fstat() implementation for Windows.
|
||||
Use CRT fstat on temporarily allocated file descriptor.
|
||||
Patch file size, because size that fstat returns is not
|
||||
reliable (may be outdated)
|
||||
*/
|
||||
int my_win_fstat(File fd, struct _stati64 *buf)
|
||||
{
|
||||
int crt_fd;
|
||||
int retval;
|
||||
HANDLE hFile, hDup;
|
||||
|
||||
DBUG_ENTER("my_win_fstat");
|
||||
|
||||
hFile= my_get_osfhandle(fd);
|
||||
if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(),
|
||||
&hDup ,0,FALSE,DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
retval= _fstati64(crt_fd, buf);
|
||||
if(retval == 0)
|
||||
{
|
||||
/* File size returned by stat is not accurate (may be outdated), fix it*/
|
||||
GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size)));
|
||||
}
|
||||
_close(crt_fd);
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_stat( const char *path, struct _stati64 *buf)
|
||||
{
|
||||
DBUG_ENTER("my_win_stat");
|
||||
if(_stati64( path, buf) == 0)
|
||||
{
|
||||
/* File size returned by stat is not accurate (may be outdated), fix it*/
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
if (GetFileAttributesEx(path, GetFileExInfoStandard, &data))
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.LowPart= data.nFileSizeLow;
|
||||
li.HighPart= data.nFileSizeHigh;
|
||||
buf->st_size= li.QuadPart;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_fsync(File fd)
|
||||
{
|
||||
DBUG_ENTER("my_win_fsync");
|
||||
if(FlushFileBuffers(my_get_osfhandle(fd)))
|
||||
DBUG_RETURN(0);
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int my_win_dup(File fd)
|
||||
{
|
||||
HANDLE hDup;
|
||||
DBUG_ENTER("my_win_dup");
|
||||
if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd),
|
||||
GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd)));
|
||||
}
|
||||
my_osmaperr(GetLastError());
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
#endif /*_WIN32*/
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,33 +14,23 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*****************************************************************************
|
||||
** Simulation of posix threads calls for WIN95 and NT
|
||||
** Simulation of posix threads calls for Windows
|
||||
*****************************************************************************/
|
||||
|
||||
#if defined (_WIN32)
|
||||
/* SAFE_MUTEX will not work until the thread structure is up to date */
|
||||
#undef SAFE_MUTEX
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#if defined(THREAD) && defined(__WIN__)
|
||||
#include <m_string.h>
|
||||
#undef getpid
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
|
||||
static pthread_mutex_t THR_LOCK_thread;
|
||||
static void install_sigabrt_handler(void);
|
||||
|
||||
struct pthread_map
|
||||
struct thread_start_parameter
|
||||
{
|
||||
HANDLE pthreadself;
|
||||
pthread_handler func;
|
||||
void *param;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
void win_pthread_init(void)
|
||||
{
|
||||
pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Adapter to @c pthread_mutex_trylock()
|
||||
|
||||
@@ -62,81 +52,101 @@ win_pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** We have tried to use '_beginthreadex' instead of '_beginthread' here
|
||||
** but in this case the program leaks about 512 characters for each
|
||||
** created thread !
|
||||
** As we want to save the created thread handler for other threads to
|
||||
** use and to be returned by pthread_self() (instead of the Win32 pseudo
|
||||
** handler), we have to go trough pthread_start() to catch the returned handler
|
||||
** in the new thread.
|
||||
*/
|
||||
|
||||
pthread_handler_t pthread_start(void *param)
|
||||
static unsigned int __stdcall pthread_start(void *p)
|
||||
{
|
||||
pthread_handler func=((struct pthread_map *) param)->func;
|
||||
void *func_param=((struct pthread_map *) param)->param;
|
||||
my_thread_init(); /* Will always succeed in windows */
|
||||
pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beginthread to return */
|
||||
win_pthread_self=((struct pthread_map *) param)->pthreadself;
|
||||
pthread_mutex_unlock(&THR_LOCK_thread);
|
||||
free((char*) param); /* Free param from create */
|
||||
pthread_exit((void*) (*func)(func_param));
|
||||
return 0; /* Safety */
|
||||
struct thread_start_parameter *par= (struct thread_start_parameter *)p;
|
||||
pthread_handler func= par->func;
|
||||
void *arg= par->arg;
|
||||
free(p);
|
||||
(*func)(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
|
||||
pthread_handler func, void *param)
|
||||
int pthread_create(pthread_t *thread_id, const pthread_attr_t *attr,
|
||||
pthread_handler func, void *param)
|
||||
{
|
||||
HANDLE hThread;
|
||||
struct pthread_map *map;
|
||||
uintptr_t handle;
|
||||
struct thread_start_parameter *par;
|
||||
unsigned int stack_size;
|
||||
DBUG_ENTER("pthread_create");
|
||||
|
||||
if (!(map=malloc(sizeof(*map))))
|
||||
DBUG_RETURN(-1);
|
||||
map->func=func;
|
||||
map->param=param;
|
||||
pthread_mutex_lock(&THR_LOCK_thread);
|
||||
#ifdef __BORLANDC__
|
||||
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
|
||||
attr->dwStackSize ? attr->dwStackSize :
|
||||
65535, (void*) map);
|
||||
#else
|
||||
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
|
||||
attr->dwStackSize ? attr->dwStackSize :
|
||||
65535, (void*) map);
|
||||
#endif
|
||||
DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
|
||||
*thread_id=map->pthreadself=hThread;
|
||||
pthread_mutex_unlock(&THR_LOCK_thread);
|
||||
par= (struct thread_start_parameter *)malloc(sizeof(*par));
|
||||
if (!par)
|
||||
goto error_return;
|
||||
|
||||
if (hThread == (HANDLE) -1)
|
||||
{
|
||||
int error=errno;
|
||||
DBUG_PRINT("error",
|
||||
("Can't create thread to handle request (error %d)",error));
|
||||
DBUG_RETURN(error ? error : -1);
|
||||
}
|
||||
VOID(SetThreadPriority(hThread, attr->priority)) ;
|
||||
par->func= func;
|
||||
par->arg= param;
|
||||
stack_size= attr?attr->dwStackSize:0;
|
||||
|
||||
handle= _beginthreadex(NULL, stack_size , pthread_start, par, 0, thread_id);
|
||||
if (!handle)
|
||||
goto error_return;
|
||||
DBUG_PRINT("info", ("thread id=%u",*thread_id));
|
||||
|
||||
/* Do not need thread handle, close it */
|
||||
CloseHandle((HANDLE)handle);
|
||||
DBUG_RETURN(0);
|
||||
|
||||
error_return:
|
||||
DBUG_PRINT("error",
|
||||
("Can't create thread to handle request (error %d)",errno));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
void pthread_exit(void *a)
|
||||
{
|
||||
_endthread();
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
/* This is neaded to get the macro pthread_setspecific to work */
|
||||
|
||||
int win_pthread_setspecific(void *a,void *b,uint length)
|
||||
int pthread_join(pthread_t thread, void **value_ptr)
|
||||
{
|
||||
memcpy(a,b,length);
|
||||
DWORD ret;
|
||||
HANDLE handle;
|
||||
|
||||
handle= OpenThread(SYNCHRONIZE, FALSE, thread);
|
||||
if (!handle)
|
||||
{
|
||||
errno= EINVAL;
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
ret= WaitForSingleObject(handle, INFINITE);
|
||||
|
||||
if(ret != WAIT_OBJECT_0)
|
||||
{
|
||||
errno= EINVAL;
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return 0;
|
||||
|
||||
error_return:
|
||||
if(handle)
|
||||
CloseHandle(handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pthread_cancel(pthread_t thread)
|
||||
{
|
||||
|
||||
HANDLE handle= 0;
|
||||
BOOL ok= FALSE;
|
||||
|
||||
handle= OpenThread(THREAD_TERMINATE, FALSE, thread);
|
||||
if (handle)
|
||||
{
|
||||
ok= TerminateThread(handle,0);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
if (ok)
|
||||
return 0;
|
||||
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
One time initialization. For simplicity, we assume initializer thread
|
||||
@@ -145,8 +155,19 @@ int win_pthread_setspecific(void *a,void *b,uint length)
|
||||
int my_pthread_once(my_pthread_once_t *once_control,
|
||||
void (*init_routine)(void))
|
||||
{
|
||||
LONG state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
|
||||
MY_PTHREAD_ONCE_INIT);
|
||||
LONG state;
|
||||
|
||||
/*
|
||||
Do "dirty" read to find out if initialization is already done, to
|
||||
save an interlocked operation in common case. Memory barriers are ensured by
|
||||
Visual C++ volatile implementation.
|
||||
*/
|
||||
if (*once_control == MY_PTHREAD_ONCE_DONE)
|
||||
return 0;
|
||||
|
||||
state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
|
||||
MY_PTHREAD_ONCE_INIT);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case MY_PTHREAD_ONCE_INIT:
|
||||
@@ -168,5 +189,4 @@ int my_pthread_once(my_pthread_once_t *once_control,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
/* Write a chunk of bytes to a file */
|
||||
|
||||
size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
{
|
||||
size_t writenbytes, written;
|
||||
size_t writtenbytes, written;
|
||||
uint errors;
|
||||
DBUG_ENTER("my_write");
|
||||
DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
|
||||
Filedes, (long) Buffer, (ulong) Count, MyFlags));
|
||||
errors=0; written=0;
|
||||
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
|
||||
Filedes, Buffer, (ulong) Count, MyFlags));
|
||||
errors= 0; written= 0;
|
||||
|
||||
/* The behavior of write(fd, buf, 0) is not portable */
|
||||
if (unlikely(!Count))
|
||||
@@ -35,22 +35,26 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if ((writenbytes= write(Filedes, Buffer, Count)) == Count)
|
||||
#ifdef _WIN32
|
||||
writtenbytes= my_win_write(Filedes, Buffer, Count);
|
||||
#else
|
||||
writtenbytes= write(Filedes, Buffer, Count);
|
||||
#endif
|
||||
if (writtenbytes == Count)
|
||||
break;
|
||||
if (writenbytes != (size_t) -1)
|
||||
if (writtenbytes != (size_t) -1)
|
||||
{ /* Safeguard */
|
||||
written+=writenbytes;
|
||||
Buffer+=writenbytes;
|
||||
Count-=writenbytes;
|
||||
written+= writtenbytes;
|
||||
Buffer+= writtenbytes;
|
||||
Count-= writtenbytes;
|
||||
}
|
||||
my_errno=errno;
|
||||
my_errno= errno;
|
||||
DBUG_PRINT("error",("Write only %ld bytes, error: %d",
|
||||
(long) writenbytes, my_errno));
|
||||
(long) writtenbytes, my_errno));
|
||||
#ifndef NO_BACKGROUND
|
||||
#ifdef THREAD
|
||||
if (my_thread_var->abort)
|
||||
MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
|
||||
#endif
|
||||
|
||||
if ((my_errno == ENOSPC || my_errno == EDQUOT) &&
|
||||
(MyFlags & MY_WAIT_IF_FULL))
|
||||
{
|
||||
@@ -59,19 +63,19 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((writenbytes == 0 || writenbytes == (size_t) -1))
|
||||
if ((writtenbytes == 0 || writtenbytes == (size_t) -1))
|
||||
{
|
||||
if (my_errno == EINTR)
|
||||
{
|
||||
DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld",
|
||||
(long) writenbytes));
|
||||
(long) writtenbytes));
|
||||
continue; /* Interrupted */
|
||||
}
|
||||
|
||||
if (!writenbytes && !errors++) /* Retry once */
|
||||
if (!writtenbytes && !errors++) /* Retry once */
|
||||
{
|
||||
/* We may come here if the file quota is exeeded */
|
||||
errno=EFBIG; /* Assume this is the error */
|
||||
errno= EFBIG; /* Assume this is the error */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -92,5 +96,5 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
|
||||
}
|
||||
if (MyFlags & (MY_NABP | MY_FNABP))
|
||||
DBUG_RETURN(0); /* Want only errors */
|
||||
DBUG_RETURN(writenbytes+written);
|
||||
DBUG_RETURN(writtenbytes+written);
|
||||
} /* my_write */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -24,14 +24,52 @@
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef THREAD
|
||||
#include <my_pthread.h>
|
||||
extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
|
||||
extern pthread_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net;
|
||||
extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
|
||||
#else
|
||||
#include <my_no_pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
|
||||
#if !defined(HAVE_PREAD) && !defined(_WIN32)
|
||||
extern PSI_mutex_key key_my_file_info_mutex;
|
||||
#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */
|
||||
|
||||
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
|
||||
extern PSI_mutex_key key_LOCK_localtime_r;
|
||||
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
|
||||
|
||||
#ifndef HAVE_GETHOSTBYNAME_R
|
||||
extern PSI_mutex_key key_LOCK_gethostbyname_r;
|
||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||
|
||||
extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
|
||||
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
|
||||
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
|
||||
key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc,
|
||||
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
|
||||
key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time,
|
||||
key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
|
||||
|
||||
extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
|
||||
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
|
||||
key_THR_COND_threads;
|
||||
|
||||
#ifdef USE_ALARM_THREAD
|
||||
extern PSI_thread_key key_thread_alarm;
|
||||
#endif /* USE_ALARM_THREAD */
|
||||
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
|
||||
extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net;
|
||||
extern mysql_mutex_t THR_LOCK_charset, THR_LOCK_time;
|
||||
|
||||
#include <mysql/psi/mysql_file.h>
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
#ifdef HUGETLB_USE_PROC_MEMINFO
|
||||
extern PSI_file_key key_file_proc_meminfo;
|
||||
#endif /* HUGETLB_USE_PROC_MEMINFO */
|
||||
extern PSI_file_key key_file_charset, key_file_cnf;
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
/*
|
||||
EDQUOT is used only in 3 C files only in mysys/. If it does not exist on
|
||||
@@ -42,3 +80,28 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
|
||||
#endif
|
||||
|
||||
void my_error_unregister_all(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/stat.h>
|
||||
/* my_winfile.c exports, should not be used outside mysys */
|
||||
extern File my_win_open(const char *path, int oflag);
|
||||
extern int my_win_close(File fd);
|
||||
extern size_t my_win_read(File fd, uchar *buffer, size_t count);
|
||||
extern size_t my_win_write(File fd, const uchar *buffer, size_t count);
|
||||
extern size_t my_win_pread(File fd, uchar *buffer, size_t count,
|
||||
my_off_t offset);
|
||||
extern size_t my_win_pwrite(File fd, const uchar *buffer, size_t count,
|
||||
my_off_t offset);
|
||||
extern my_off_t my_win_lseek(File fd, my_off_t pos, int whence);
|
||||
extern int my_win_chsize(File fd, my_off_t newlength);
|
||||
extern FILE* my_win_fopen(const char *filename, const char *type);
|
||||
extern File my_win_fclose(FILE *file);
|
||||
extern File my_win_fileno(FILE *file);
|
||||
extern FILE* my_win_fdopen(File Filedes, const char *type);
|
||||
extern int my_win_stat(const char *path, struct _stati64 *buf);
|
||||
extern int my_win_fstat(File fd, struct _stati64 *buf);
|
||||
extern int my_win_fsync(File fd);
|
||||
extern File my_win_dup(File fd);
|
||||
extern File my_win_sopen(const char *path, int oflag, int shflag, int perm);
|
||||
extern File my_open_osfhandle(HANDLE handle, int oflag);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
get_ptr_compare(len) returns a pointer to a optimal byte-compare function
|
||||
for a array of stringpointer where all strings have size len.
|
||||
The bytes are compare as unsigned chars.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <myisampack.h>
|
||||
|
||||
#ifdef __sun
|
||||
/*
|
||||
* On Solaris, memcmp() is normally faster than the unrolled ptr_compare_N
|
||||
* functions, as memcmp() is usually a platform-specific implementation
|
||||
* written in assembler, provided in /usr/lib/libc/libc_hwcap*.so.1.
|
||||
* This implementation is also usually faster than the built-in memcmp
|
||||
* supplied by GCC, so it is recommended to build with "-fno-builtin-memcmp"
|
||||
* in CFLAGS if building with GCC on Solaris.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int native_compare(size_t *length, unsigned char **a, unsigned char **b)
|
||||
{
|
||||
return memcmp(*a, *b, *length);
|
||||
}
|
||||
|
||||
#else /* __sun */
|
||||
|
||||
static int ptr_compare(size_t *compare_length, uchar **a, uchar **b);
|
||||
static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b);
|
||||
static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b);
|
||||
static int ptr_compare_2(size_t *compare_length, uchar **a, uchar **b);
|
||||
static int ptr_compare_3(size_t *compare_length, uchar **a, uchar **b);
|
||||
#endif /* __sun */
|
||||
|
||||
/* Get a pointer to a optimal byte-compare function for a given size */
|
||||
|
||||
#ifdef __sun
|
||||
qsort2_cmp get_ptr_compare (size_t size __attribute__((unused)))
|
||||
{
|
||||
return (qsort2_cmp) native_compare;
|
||||
}
|
||||
#else
|
||||
qsort2_cmp get_ptr_compare (size_t size)
|
||||
{
|
||||
if (size < 4)
|
||||
return (qsort2_cmp) ptr_compare;
|
||||
switch (size & 3) {
|
||||
case 0: return (qsort2_cmp) ptr_compare_0;
|
||||
case 1: return (qsort2_cmp) ptr_compare_1;
|
||||
case 2: return (qsort2_cmp) ptr_compare_2;
|
||||
case 3: return (qsort2_cmp) ptr_compare_3;
|
||||
}
|
||||
return 0; /* Impossible */
|
||||
}
|
||||
#endif /* __sun */
|
||||
|
||||
|
||||
/*
|
||||
Compare to keys to see witch is smaller.
|
||||
Loop unrolled to make it quick !!
|
||||
*/
|
||||
|
||||
#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
|
||||
|
||||
#ifndef __sun
|
||||
|
||||
static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
|
||||
{
|
||||
reg3 int length= *compare_length;
|
||||
reg1 uchar *first,*last;
|
||||
|
||||
first= *a; last= *b;
|
||||
while (--length)
|
||||
{
|
||||
if (*first++ != *last++)
|
||||
return (int) first[-1] - (int) last[-1];
|
||||
}
|
||||
return (int) first[0] - (int) last[0];
|
||||
}
|
||||
|
||||
|
||||
static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b)
|
||||
{
|
||||
reg3 int length= *compare_length;
|
||||
reg1 uchar *first,*last;
|
||||
|
||||
first= *a; last= *b;
|
||||
loop:
|
||||
cmp(0);
|
||||
cmp(1);
|
||||
cmp(2);
|
||||
cmp(3);
|
||||
if ((length-=4))
|
||||
{
|
||||
first+=4;
|
||||
last+=4;
|
||||
goto loop;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b)
|
||||
{
|
||||
reg3 int length= *compare_length-1;
|
||||
reg1 uchar *first,*last;
|
||||
|
||||
first= *a+1; last= *b+1;
|
||||
cmp(-1);
|
||||
loop:
|
||||
cmp(0);
|
||||
cmp(1);
|
||||
cmp(2);
|
||||
cmp(3);
|
||||
if ((length-=4))
|
||||
{
|
||||
first+=4;
|
||||
last+=4;
|
||||
goto loop;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b)
|
||||
{
|
||||
reg3 int length= *compare_length-2;
|
||||
reg1 uchar *first,*last;
|
||||
|
||||
first= *a +2 ; last= *b +2;
|
||||
cmp(-2);
|
||||
cmp(-1);
|
||||
loop:
|
||||
cmp(0);
|
||||
cmp(1);
|
||||
cmp(2);
|
||||
cmp(3);
|
||||
if ((length-=4))
|
||||
{
|
||||
first+=4;
|
||||
last+=4;
|
||||
goto loop;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int ptr_compare_3(size_t *compare_length,uchar **a, uchar **b)
|
||||
{
|
||||
reg3 int length= *compare_length-3;
|
||||
reg1 uchar *first,*last;
|
||||
|
||||
first= *a +3 ; last= *b +3;
|
||||
cmp(-3);
|
||||
cmp(-2);
|
||||
cmp(-1);
|
||||
loop:
|
||||
cmp(0);
|
||||
cmp(1);
|
||||
cmp(2);
|
||||
cmp(3);
|
||||
if ((length-=4))
|
||||
{
|
||||
first+=4;
|
||||
last+=4;
|
||||
goto loop;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* !__sun */
|
||||
|
||||
void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos)
|
||||
{
|
||||
switch (pack_length) {
|
||||
#if SIZEOF_OFF_T > 4
|
||||
case 8: mi_int8store(buff,pos); break;
|
||||
case 7: mi_int7store(buff,pos); break;
|
||||
case 6: mi_int6store(buff,pos); break;
|
||||
case 5: mi_int5store(buff,pos); break;
|
||||
#endif
|
||||
case 4: mi_int4store(buff,pos); break;
|
||||
case 3: mi_int3store(buff,pos); break;
|
||||
case 2: mi_int2store(buff,pos); break;
|
||||
case 1: buff[0]= (uchar) pos; break;
|
||||
default: DBUG_ASSERT(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
my_off_t my_get_ptr(uchar *ptr, size_t pack_length)
|
||||
{
|
||||
my_off_t pos;
|
||||
switch (pack_length) {
|
||||
#if SIZEOF_OFF_T > 4
|
||||
case 8: pos= (my_off_t) mi_uint8korr(ptr); break;
|
||||
case 7: pos= (my_off_t) mi_uint7korr(ptr); break;
|
||||
case 6: pos= (my_off_t) mi_uint6korr(ptr); break;
|
||||
case 5: pos= (my_off_t) mi_uint5korr(ptr); break;
|
||||
#endif
|
||||
case 4: pos= (my_off_t) mi_uint4korr(ptr); break;
|
||||
case 3: pos= (my_off_t) mi_uint3korr(ptr); break;
|
||||
case 2: pos= (my_off_t) mi_uint2korr(ptr); break;
|
||||
case 1: pos= (my_off_t) *(uchar*) ptr; break;
|
||||
default: DBUG_ASSERT(0); return 0;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,687 @@
|
||||
/* Copyright (C) 2000, 2005 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Code for generell handling of priority Queues.
|
||||
Implemention of queues from "Algoritms in C" by Robert Sedgewick.
|
||||
An optimisation of _downheap suggested in Exercise 7.51 in "Data
|
||||
Structures & Algorithms in C++" by Mark Allen Weiss, Second Edition
|
||||
was implemented by Mikael Ronstrom 2005. Also the O(N) algorithm
|
||||
of queue_fix was implemented.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include "mysys_err.h"
|
||||
#include <queues.h>
|
||||
|
||||
|
||||
/*
|
||||
Init queue
|
||||
|
||||
SYNOPSIS
|
||||
init_queue()
|
||||
queue Queue to initialise
|
||||
max_elements Max elements that will be put in queue
|
||||
offset_to_key Offset to key in element stored in queue
|
||||
Used when sending pointers to compare function
|
||||
max_at_top Set to 1 if you want biggest element on top.
|
||||
compare Compare function for elements, takes 3 arguments.
|
||||
first_cmp_arg First argument to compare function
|
||||
|
||||
NOTES
|
||||
Will allocate max_element pointers for queue array
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Could not allocate memory
|
||||
*/
|
||||
|
||||
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
|
||||
pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
|
||||
void *first_cmp_arg)
|
||||
{
|
||||
DBUG_ENTER("init_queue");
|
||||
if ((queue->root= (uchar **) my_malloc((max_elements+1)*sizeof(void*),
|
||||
MYF(MY_WME))) == 0)
|
||||
DBUG_RETURN(1);
|
||||
queue->elements=0;
|
||||
queue->compare=compare;
|
||||
queue->first_cmp_arg=first_cmp_arg;
|
||||
queue->max_elements=max_elements;
|
||||
queue->offset_to_key=offset_to_key;
|
||||
queue_set_max_at_top(queue, max_at_top);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Init queue, uses init_queue internally for init work but also accepts
|
||||
auto_extent as parameter
|
||||
|
||||
SYNOPSIS
|
||||
init_queue_ex()
|
||||
queue Queue to initialise
|
||||
max_elements Max elements that will be put in queue
|
||||
offset_to_key Offset to key in element stored in queue
|
||||
Used when sending pointers to compare function
|
||||
max_at_top Set to 1 if you want biggest element on top.
|
||||
compare Compare function for elements, takes 3 arguments.
|
||||
first_cmp_arg First argument to compare function
|
||||
auto_extent When the queue is full and there is insert operation
|
||||
extend the queue.
|
||||
|
||||
NOTES
|
||||
Will allocate max_element pointers for queue array
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Could not allocate memory
|
||||
*/
|
||||
|
||||
int init_queue_ex(QUEUE *queue, uint max_elements, uint offset_to_key,
|
||||
pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
|
||||
void *first_cmp_arg, uint auto_extent)
|
||||
{
|
||||
int ret;
|
||||
DBUG_ENTER("init_queue_ex");
|
||||
|
||||
if ((ret= init_queue(queue, max_elements, offset_to_key, max_at_top, compare,
|
||||
first_cmp_arg)))
|
||||
DBUG_RETURN(ret);
|
||||
|
||||
queue->auto_extent= auto_extent;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Reinitialize queue for other usage
|
||||
|
||||
SYNOPSIS
|
||||
reinit_queue()
|
||||
queue Queue to initialise
|
||||
max_elements Max elements that will be put in queue
|
||||
offset_to_key Offset to key in element stored in queue
|
||||
Used when sending pointers to compare function
|
||||
max_at_top Set to 1 if you want biggest element on top.
|
||||
compare Compare function for elements, takes 3 arguments.
|
||||
first_cmp_arg First argument to compare function
|
||||
|
||||
NOTES
|
||||
This will delete all elements from the queue. If you don't want this,
|
||||
use resize_queue() instead.
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
EE_OUTOFMEMORY Wrong max_elements
|
||||
*/
|
||||
|
||||
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
|
||||
pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
|
||||
void *first_cmp_arg)
|
||||
{
|
||||
DBUG_ENTER("reinit_queue");
|
||||
queue->elements=0;
|
||||
queue->compare=compare;
|
||||
queue->first_cmp_arg=first_cmp_arg;
|
||||
queue->offset_to_key=offset_to_key;
|
||||
queue_set_max_at_top(queue, max_at_top);
|
||||
resize_queue(queue, max_elements);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Resize queue
|
||||
|
||||
SYNOPSIS
|
||||
resize_queue()
|
||||
queue Queue
|
||||
max_elements New max size for queue
|
||||
|
||||
NOTES
|
||||
If you resize queue to be less than the elements you have in it,
|
||||
the extra elements will be deleted
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 Error. In this case the queue is unchanged
|
||||
*/
|
||||
|
||||
int resize_queue(QUEUE *queue, uint max_elements)
|
||||
{
|
||||
uchar **new_root;
|
||||
DBUG_ENTER("resize_queue");
|
||||
if (queue->max_elements == max_elements)
|
||||
DBUG_RETURN(0);
|
||||
if ((new_root= (uchar **) my_realloc((void *)queue->root,
|
||||
(max_elements+1)*sizeof(void*),
|
||||
MYF(MY_WME))) == 0)
|
||||
DBUG_RETURN(1);
|
||||
set_if_smaller(queue->elements, max_elements);
|
||||
queue->max_elements= max_elements;
|
||||
queue->root= new_root;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Delete queue
|
||||
|
||||
SYNOPSIS
|
||||
delete_queue()
|
||||
queue Queue to delete
|
||||
|
||||
IMPLEMENTATION
|
||||
Just free allocated memory.
|
||||
|
||||
NOTES
|
||||
Can be called safely multiple times
|
||||
*/
|
||||
|
||||
void delete_queue(QUEUE *queue)
|
||||
{
|
||||
DBUG_ENTER("delete_queue");
|
||||
my_free(queue->root);
|
||||
queue->root= NULL;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Code for insert, search and delete of elements */
|
||||
|
||||
void queue_insert(register QUEUE *queue, uchar *element)
|
||||
{
|
||||
reg2 uint idx, next;
|
||||
DBUG_ASSERT(queue->elements < queue->max_elements);
|
||||
queue->root[0]= element;
|
||||
idx= ++queue->elements;
|
||||
/* max_at_top swaps the comparison if we want to order by desc */
|
||||
while ((queue->compare(queue->first_cmp_arg,
|
||||
element + queue->offset_to_key,
|
||||
queue->root[(next= idx >> 1)] +
|
||||
queue->offset_to_key) * queue->max_at_top) < 0)
|
||||
{
|
||||
queue->root[idx]= queue->root[next];
|
||||
idx= next;
|
||||
}
|
||||
queue->root[idx]= element;
|
||||
}
|
||||
|
||||
/*
|
||||
Does safe insert. If no more space left on the queue resize it.
|
||||
Return codes:
|
||||
0 - OK
|
||||
1 - Cannot allocate more memory
|
||||
2 - auto_extend is 0, the operation would
|
||||
|
||||
*/
|
||||
|
||||
int queue_insert_safe(register QUEUE *queue, uchar *element)
|
||||
{
|
||||
|
||||
if (queue->elements == queue->max_elements)
|
||||
{
|
||||
if (!queue->auto_extent)
|
||||
return 2;
|
||||
else if (resize_queue(queue, queue->max_elements + queue->auto_extent))
|
||||
return 1;
|
||||
}
|
||||
|
||||
queue_insert(queue, element);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Remove item from queue */
|
||||
/* Returns pointer to removed element */
|
||||
|
||||
uchar *queue_remove(register QUEUE *queue, uint idx)
|
||||
{
|
||||
uchar *element;
|
||||
DBUG_ASSERT(idx < queue->max_elements);
|
||||
element= queue->root[++idx]; /* Intern index starts from 1 */
|
||||
queue->root[idx]= queue->root[queue->elements--];
|
||||
_downheap(queue, idx);
|
||||
return element;
|
||||
}
|
||||
|
||||
/* Fix when element on top has been replaced */
|
||||
|
||||
#ifndef queue_replaced
|
||||
void queue_replaced(QUEUE *queue)
|
||||
{
|
||||
_downheap(queue,1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OLD_VERSION
|
||||
|
||||
void _downheap(register QUEUE *queue, uint idx)
|
||||
{
|
||||
uchar *element;
|
||||
uint elements,half_queue,offset_to_key, next_index;
|
||||
my_bool first= TRUE;
|
||||
uint start_idx= idx;
|
||||
|
||||
offset_to_key=queue->offset_to_key;
|
||||
element=queue->root[idx];
|
||||
half_queue=(elements=queue->elements) >> 1;
|
||||
|
||||
while (idx <= half_queue)
|
||||
{
|
||||
next_index=idx+idx;
|
||||
if (next_index < elements &&
|
||||
(queue->compare(queue->first_cmp_arg,
|
||||
queue->root[next_index]+offset_to_key,
|
||||
queue->root[next_index+1]+offset_to_key) *
|
||||
queue->max_at_top) > 0)
|
||||
next_index++;
|
||||
if (first &&
|
||||
(((queue->compare(queue->first_cmp_arg,
|
||||
queue->root[next_index]+offset_to_key,
|
||||
element+offset_to_key) * queue->max_at_top) >= 0)))
|
||||
{
|
||||
queue->root[idx]= element;
|
||||
return;
|
||||
}
|
||||
queue->root[idx]=queue->root[next_index];
|
||||
idx=next_index;
|
||||
first= FALSE;
|
||||
}
|
||||
|
||||
next_index= idx >> 1;
|
||||
while (next_index > start_idx)
|
||||
{
|
||||
if ((queue->compare(queue->first_cmp_arg,
|
||||
queue->root[next_index]+offset_to_key,
|
||||
element+offset_to_key) *
|
||||
queue->max_at_top) < 0)
|
||||
break;
|
||||
queue->root[idx]=queue->root[next_index];
|
||||
idx=next_index;
|
||||
next_index= idx >> 1;
|
||||
}
|
||||
queue->root[idx]=element;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
The old _downheap version is kept for comparisons with the benchmark
|
||||
suit or new benchmarks anyone wants to run for comparisons.
|
||||
*/
|
||||
/* Fix heap when index have changed */
|
||||
void _downheap(register QUEUE *queue, uint idx)
|
||||
{
|
||||
uchar *element;
|
||||
uint elements,half_queue,next_index,offset_to_key;
|
||||
|
||||
offset_to_key=queue->offset_to_key;
|
||||
element=queue->root[idx];
|
||||
half_queue=(elements=queue->elements) >> 1;
|
||||
|
||||
while (idx <= half_queue)
|
||||
{
|
||||
next_index=idx+idx;
|
||||
if (next_index < elements &&
|
||||
(queue->compare(queue->first_cmp_arg,
|
||||
queue->root[next_index]+offset_to_key,
|
||||
queue->root[next_index+1]+offset_to_key) *
|
||||
queue->max_at_top) > 0)
|
||||
next_index++;
|
||||
if ((queue->compare(queue->first_cmp_arg,
|
||||
queue->root[next_index]+offset_to_key,
|
||||
element+offset_to_key) * queue->max_at_top) >= 0)
|
||||
break;
|
||||
queue->root[idx]=queue->root[next_index];
|
||||
idx=next_index;
|
||||
}
|
||||
queue->root[idx]=element;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Fix heap when every element was changed.
|
||||
*/
|
||||
|
||||
void queue_fix(QUEUE *queue)
|
||||
{
|
||||
uint i;
|
||||
for (i= queue->elements >> 1; i > 0; i--)
|
||||
_downheap(queue, i);
|
||||
}
|
||||
|
||||
#ifdef MAIN
|
||||
/*
|
||||
A test program for the priority queue implementation.
|
||||
It can also be used to benchmark changes of the implementation
|
||||
Build by doing the following in the directory mysys
|
||||
make test_priority_queue
|
||||
./test_priority_queue
|
||||
|
||||
Written by Mikael Ronström, 2005
|
||||
*/
|
||||
|
||||
static uint num_array[1025];
|
||||
static uint tot_no_parts= 0;
|
||||
static uint tot_no_loops= 0;
|
||||
static uint expected_part= 0;
|
||||
static uint expected_num= 0;
|
||||
static bool max_ind= 0;
|
||||
static bool fix_used= 0;
|
||||
static ulonglong start_time= 0;
|
||||
|
||||
static bool is_divisible_by(uint num, uint divisor)
|
||||
{
|
||||
uint quotient= num / divisor;
|
||||
if (quotient * divisor == num)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void calculate_next()
|
||||
{
|
||||
uint part= expected_part, num= expected_num;
|
||||
uint no_parts= tot_no_parts;
|
||||
if (max_ind)
|
||||
{
|
||||
do
|
||||
{
|
||||
while (++part <= no_parts)
|
||||
{
|
||||
if (is_divisible_by(num, part) &&
|
||||
(num <= ((1 << 21) + part)))
|
||||
{
|
||||
expected_part= part;
|
||||
expected_num= num;
|
||||
return;
|
||||
}
|
||||
}
|
||||
part= 0;
|
||||
} while (--num);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
while (--part > 0)
|
||||
{
|
||||
if (is_divisible_by(num, part))
|
||||
{
|
||||
expected_part= part;
|
||||
expected_num= num;
|
||||
return;
|
||||
}
|
||||
}
|
||||
part= no_parts + 1;
|
||||
} while (++num);
|
||||
}
|
||||
}
|
||||
|
||||
void calculate_end_next(uint part)
|
||||
{
|
||||
uint no_parts= tot_no_parts, num;
|
||||
num_array[part]= 0;
|
||||
if (max_ind)
|
||||
{
|
||||
expected_num= 0;
|
||||
for (part= no_parts; part > 0 ; part--)
|
||||
{
|
||||
if (num_array[part])
|
||||
{
|
||||
num= num_array[part] & 0x3FFFFF;
|
||||
if (num >= expected_num)
|
||||
{
|
||||
expected_num= num;
|
||||
expected_part= part;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expected_num == 0)
|
||||
expected_part= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
expected_num= 0xFFFFFFFF;
|
||||
for (part= 1; part <= no_parts; part++)
|
||||
{
|
||||
if (num_array[part])
|
||||
{
|
||||
num= num_array[part] & 0x3FFFFF;
|
||||
if (num <= expected_num)
|
||||
{
|
||||
expected_num= num;
|
||||
expected_part= part;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (expected_num == 0xFFFFFFFF)
|
||||
expected_part= 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
static int test_compare(void *null_arg, uchar *a, uchar *b)
|
||||
{
|
||||
uint a_num= (*(uint*)a) & 0x3FFFFF;
|
||||
uint b_num= (*(uint*)b) & 0x3FFFFF;
|
||||
uint a_part, b_part;
|
||||
if (a_num > b_num)
|
||||
return +1;
|
||||
if (a_num < b_num)
|
||||
return -1;
|
||||
a_part= (*(uint*)a) >> 22;
|
||||
b_part= (*(uint*)b) >> 22;
|
||||
if (a_part < b_part)
|
||||
return +1;
|
||||
if (a_part > b_part)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool check_num(uint num_part)
|
||||
{
|
||||
uint part= num_part >> 22;
|
||||
uint num= num_part & 0x3FFFFF;
|
||||
if (part == expected_part)
|
||||
if (num == expected_num)
|
||||
return FALSE;
|
||||
printf("Expect part %u Expect num 0x%x got part %u num 0x%x max_ind %u fix_used %u \n",
|
||||
expected_part, expected_num, part, num, max_ind, fix_used);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
void perform_insert(QUEUE *queue)
|
||||
{
|
||||
uint i= 1, no_parts= tot_no_parts;
|
||||
uint backward_start= 0;
|
||||
|
||||
expected_part= 1;
|
||||
expected_num= 1;
|
||||
|
||||
if (max_ind)
|
||||
backward_start= 1 << 21;
|
||||
|
||||
do
|
||||
{
|
||||
uint num= (i + backward_start);
|
||||
if (max_ind)
|
||||
{
|
||||
while (!is_divisible_by(num, i))
|
||||
num--;
|
||||
if (max_ind && (num > expected_num ||
|
||||
(num == expected_num && i < expected_part)))
|
||||
{
|
||||
expected_num= num;
|
||||
expected_part= i;
|
||||
}
|
||||
}
|
||||
num_array[i]= num + (i << 22);
|
||||
if (fix_used)
|
||||
queue_element(queue, i-1)= (uchar*)&num_array[i];
|
||||
else
|
||||
queue_insert(queue, (uchar*)&num_array[i]);
|
||||
} while (++i <= no_parts);
|
||||
if (fix_used)
|
||||
{
|
||||
queue->elements= no_parts;
|
||||
queue_fix(queue);
|
||||
}
|
||||
}
|
||||
|
||||
bool perform_ins_del(QUEUE *queue, bool max_ind)
|
||||
{
|
||||
uint i= 0, no_loops= tot_no_loops, j= tot_no_parts;
|
||||
do
|
||||
{
|
||||
uint num_part= *(uint*)queue_top(queue);
|
||||
uint part= num_part >> 22;
|
||||
if (check_num(num_part))
|
||||
return TRUE;
|
||||
if (j++ >= no_loops)
|
||||
{
|
||||
calculate_end_next(part);
|
||||
queue_remove(queue, (uint) 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
calculate_next();
|
||||
if (max_ind)
|
||||
num_array[part]-= part;
|
||||
else
|
||||
num_array[part]+= part;
|
||||
queue_top(queue)= (uchar*)&num_array[part];
|
||||
queue_replaced(queue);
|
||||
}
|
||||
} while (++i < no_loops);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool do_test(uint no_parts, uint l_max_ind, bool l_fix_used)
|
||||
{
|
||||
QUEUE queue;
|
||||
bool result;
|
||||
max_ind= l_max_ind;
|
||||
fix_used= l_fix_used;
|
||||
init_queue(&queue, no_parts, 0, max_ind, test_compare, NULL);
|
||||
tot_no_parts= no_parts;
|
||||
tot_no_loops= 1024;
|
||||
perform_insert(&queue);
|
||||
if ((result= perform_ins_del(&queue, max_ind)))
|
||||
delete_queue(&queue);
|
||||
if (result)
|
||||
{
|
||||
printf("Error\n");
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void start_measurement()
|
||||
{
|
||||
start_time= my_getsystime();
|
||||
}
|
||||
|
||||
static void stop_measurement()
|
||||
{
|
||||
ulonglong stop_time= my_getsystime();
|
||||
uint time_in_micros;
|
||||
stop_time-= start_time;
|
||||
stop_time/= 10; /* Convert to microseconds */
|
||||
time_in_micros= (uint)stop_time;
|
||||
printf("Time expired is %u microseconds \n", time_in_micros);
|
||||
}
|
||||
|
||||
static void benchmark_test()
|
||||
{
|
||||
QUEUE queue_real;
|
||||
QUEUE *queue= &queue_real;
|
||||
uint i, add;
|
||||
fix_used= TRUE;
|
||||
max_ind= FALSE;
|
||||
tot_no_parts= 1024;
|
||||
init_queue(queue, tot_no_parts, 0, max_ind, test_compare, NULL);
|
||||
/*
|
||||
First benchmark whether queue_fix is faster than using queue_insert
|
||||
for sizes of 16 partitions.
|
||||
*/
|
||||
for (tot_no_parts= 2, add=2; tot_no_parts < 128;
|
||||
tot_no_parts+= add, add++)
|
||||
{
|
||||
printf("Start benchmark queue_fix, tot_no_parts= %u \n", tot_no_parts);
|
||||
start_measurement();
|
||||
for (i= 0; i < 128; i++)
|
||||
{
|
||||
perform_insert(queue);
|
||||
queue_remove_all(queue);
|
||||
}
|
||||
stop_measurement();
|
||||
|
||||
fix_used= FALSE;
|
||||
printf("Start benchmark queue_insert\n");
|
||||
start_measurement();
|
||||
for (i= 0; i < 128; i++)
|
||||
{
|
||||
perform_insert(queue);
|
||||
queue_remove_all(queue);
|
||||
}
|
||||
stop_measurement();
|
||||
}
|
||||
/*
|
||||
Now benchmark insertion and deletion of 16400 elements.
|
||||
Used in consecutive runs this shows whether the optimised _downheap
|
||||
is faster than the standard implementation.
|
||||
*/
|
||||
printf("Start benchmarking _downheap \n");
|
||||
start_measurement();
|
||||
perform_insert(queue);
|
||||
for (i= 0; i < 65536; i++)
|
||||
{
|
||||
uint num, part;
|
||||
num= *(uint*)queue_top(queue);
|
||||
num+= 16;
|
||||
part= num >> 22;
|
||||
num_array[part]= num;
|
||||
queue_top(queue)= (uchar*)&num_array[part];
|
||||
queue_replaced(queue);
|
||||
}
|
||||
for (i= 0; i < 16; i++)
|
||||
queue_remove(queue, (uint) 0);
|
||||
queue_remove_all(queue);
|
||||
stop_measurement();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, add= 1;
|
||||
for (i= 1; i < 1024; i+=add, add++)
|
||||
{
|
||||
printf("Start test for priority queue of size %u\n", i);
|
||||
if (do_test(i, 0, 1))
|
||||
return -1;
|
||||
if (do_test(i, 1, 1))
|
||||
return -1;
|
||||
if (do_test(i, 0, 0))
|
||||
return -1;
|
||||
if (do_test(i, 1, 0))
|
||||
return -1;
|
||||
}
|
||||
benchmark_test();
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,576 +0,0 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
* Memory sub-system, written by Bjorn Benson
|
||||
Fixed to use my_sys scheme by Michael Widenius
|
||||
|
||||
[This posting refers to an article entitled "oops, corrupted memory
|
||||
again!" in net.lang.c. I am posting it here because it is source.]
|
||||
|
||||
My tool for approaching this problem is to build another level of data
|
||||
abstraction on top of malloc() and free() that implements some checking.
|
||||
This does a number of things for you:
|
||||
- Checks for overruns and underruns on allocated data
|
||||
- Keeps track of where in the program the memory was malloc'ed
|
||||
- Reports on pieces of memory that were not free'ed
|
||||
- Records some statistics such as maximum memory used
|
||||
- Marks newly malloc'ed and newly free'ed memory with special values
|
||||
You can use this scheme to:
|
||||
- Find bugs such as overrun, underrun, etc because you know where
|
||||
a piece of data was malloc'ed and where it was free'ed
|
||||
- Find bugs where memory was not free'ed
|
||||
- Find bugs where newly malloc'ed memory is used without initializing
|
||||
- Find bugs where newly free'ed memory is still used
|
||||
- Determine how much memory your program really uses
|
||||
- and other things
|
||||
|
||||
To implement my scheme you must have a C compiler that has __LINE__ and
|
||||
__FILE__ macros. If your compiler doesn't have these then (a) buy another:
|
||||
compilers that do are available on UNIX 4.2bsd based systems and the PC,
|
||||
and probably on other machines; or (b) change my scheme somehow. I have
|
||||
recomendations on both these points if you would like them (e-mail please).
|
||||
|
||||
There are 4 functions in my package:
|
||||
char *NEW( uSize ) Allocate memory of uSize bytes
|
||||
(equivalent to malloc())
|
||||
char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
|
||||
free pPtr.
|
||||
(equivalent to realloc())
|
||||
FREE( pPtr ) Free memory allocated by NEW
|
||||
(equivalent to free())
|
||||
TERMINATE(file,flag) End system, report errors and stats on file
|
||||
I personally use two more functions, but have not included them here:
|
||||
char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory
|
||||
char *RENEW( pPtr, uSize )
|
||||
(equivalent to realloc())
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SAFEMALLOC
|
||||
#define SAFEMALLOC /* Get protos from my_sys */
|
||||
#endif
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include "my_static.h"
|
||||
#include "mysys_err.h"
|
||||
|
||||
ulonglong sf_malloc_mem_limit= ~(ulonglong)0;
|
||||
|
||||
#ifndef PEDANTIC_SAFEMALLOC
|
||||
/*
|
||||
Set to 1 after TERMINATE() if we had to fiddle with sf_malloc_count and
|
||||
the linked list of blocks so that _sanity() will not fuss when it
|
||||
is not supposed to
|
||||
*/
|
||||
static int sf_malloc_tampered= 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* Static functions prototypes */
|
||||
|
||||
static int check_ptr(const char *where, uchar *ptr, const char *sFile,
|
||||
uint uLine);
|
||||
static int _checkchunk(struct st_irem *pRec, const char *sFile, uint uLine);
|
||||
|
||||
/*
|
||||
Note: We only fill up the allocated block. This do not include
|
||||
malloc() roundoff or the extra space required by the irem
|
||||
structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
NEW'ed memory is filled with this value so that references to it will
|
||||
end up being very strange.
|
||||
*/
|
||||
#define ALLOC_VAL (uchar) 0xA5
|
||||
/*
|
||||
FEEE'ed memory is filled with this value so that references to it will
|
||||
end up being very strange.
|
||||
*/
|
||||
#define FREE_VAL (uchar) 0x8F
|
||||
#define MAGICKEY 0x14235296 /* A magic value for underrun key */
|
||||
|
||||
/*
|
||||
Warning: do not change the MAGICEND? values to something with the
|
||||
high bit set. Various C compilers (like the 4.2bsd one) do not do
|
||||
the sign extension right later on in this code and you will get
|
||||
erroneous errors.
|
||||
*/
|
||||
|
||||
#define MAGICEND0 0x68 /* Magic values for overrun keys */
|
||||
#define MAGICEND1 0x34 /* " */
|
||||
#define MAGICEND2 0x7A /* " */
|
||||
#define MAGICEND3 0x15 /* " */
|
||||
|
||||
|
||||
/* Allocate some memory. */
|
||||
|
||||
void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
uchar *data;
|
||||
DBUG_ENTER("_mymalloc");
|
||||
DBUG_PRINT("enter",("Size: %lu", (ulong) size));
|
||||
|
||||
if (!sf_malloc_quick)
|
||||
(void) _sanity (filename, lineno);
|
||||
|
||||
if (size + sf_malloc_cur_memory > sf_malloc_mem_limit)
|
||||
irem= 0;
|
||||
else
|
||||
{
|
||||
/* Allocate the physical memory */
|
||||
irem= (struct st_irem *) malloc (ALIGN_SIZE(sizeof(struct st_irem)) +
|
||||
sf_malloc_prehunc +
|
||||
size + /* size requested */
|
||||
4 + /* overrun mark */
|
||||
sf_malloc_endhunc);
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
free(irem);
|
||||
irem= NULL;
|
||||
});
|
||||
}
|
||||
/* Check if there isn't anymore memory avaiable */
|
||||
if (!irem)
|
||||
{
|
||||
if (MyFlags & MY_FAE)
|
||||
error_handler_hook=fatal_error_handler_hook;
|
||||
if (MyFlags & (MY_FAE+MY_WME))
|
||||
{
|
||||
char buff[256];
|
||||
my_errno=errno;
|
||||
sprintf(buff,"Out of memory at line %d, '%s'", lineno, filename);
|
||||
my_message(EE_OUTOFMEMORY, buff, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH));
|
||||
sprintf(buff,"needed %lu byte (%luk), memory in use: %lu bytes (%luk)",
|
||||
(ulong) size, (ulong) (size + 1023L) / 1024L,
|
||||
(ulong) sf_malloc_max_memory,
|
||||
(ulong) (sf_malloc_max_memory + 1023L) / 1024L);
|
||||
my_message(EE_OUTOFMEMORY, buff, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH));
|
||||
}
|
||||
DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
|
||||
(ulong) sf_malloc_max_memory, lineno, filename));
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
DBUG_SET("-d,simulate_out_of_memory"););
|
||||
if (MyFlags & MY_FAE)
|
||||
exit(1);
|
||||
DBUG_RETURN ((void*) 0);
|
||||
}
|
||||
|
||||
/* Fill up the structure */
|
||||
data= (((uchar*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
|
||||
sf_malloc_prehunc);
|
||||
*((uint32*) (data-sizeof(uint32)))= MAGICKEY;
|
||||
data[size + 0]= MAGICEND0;
|
||||
data[size + 1]= MAGICEND1;
|
||||
data[size + 2]= MAGICEND2;
|
||||
data[size + 3]= MAGICEND3;
|
||||
irem->filename= (char *) filename;
|
||||
irem->linenum= lineno;
|
||||
irem->datasize= size;
|
||||
irem->prev= NULL;
|
||||
|
||||
/* Add this remember structure to the linked list */
|
||||
pthread_mutex_lock(&THR_LOCK_malloc);
|
||||
if ((irem->next= sf_malloc_root))
|
||||
sf_malloc_root->prev= irem;
|
||||
sf_malloc_root= irem;
|
||||
|
||||
/* Keep the statistics */
|
||||
sf_malloc_cur_memory+= size;
|
||||
if (sf_malloc_cur_memory > sf_malloc_max_memory)
|
||||
sf_malloc_max_memory= sf_malloc_cur_memory;
|
||||
sf_malloc_count++;
|
||||
pthread_mutex_unlock(&THR_LOCK_malloc);
|
||||
|
||||
MEM_CHECK_ADDRESSABLE(data, size);
|
||||
/* Set the memory to the aribtrary wierd value */
|
||||
if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick)
|
||||
bfill(data, size, (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
|
||||
if (!(MyFlags & MY_ZEROFILL))
|
||||
MEM_UNDEFINED(data, size);
|
||||
/* Return a pointer to the real data */
|
||||
DBUG_PRINT("exit",("ptr: %p", data));
|
||||
if (sf_min_adress > data)
|
||||
sf_min_adress= data;
|
||||
if (sf_max_adress < data)
|
||||
sf_max_adress= data;
|
||||
DBUG_RETURN((void*) data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Allocate some new memory and move old memoryblock there.
|
||||
Free then old memoryblock
|
||||
*/
|
||||
|
||||
void *_myrealloc(register void *ptr, register size_t size,
|
||||
const char *filename, uint lineno, myf MyFlags)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
char *data;
|
||||
DBUG_ENTER("_myrealloc");
|
||||
|
||||
if (!ptr && (MyFlags & MY_ALLOW_ZERO_PTR))
|
||||
DBUG_RETURN(_mymalloc(size, filename, lineno, MyFlags));
|
||||
|
||||
if (!sf_malloc_quick)
|
||||
(void) _sanity (filename, lineno);
|
||||
|
||||
if (check_ptr("Reallocating", (uchar*) ptr, filename, lineno))
|
||||
DBUG_RETURN((uchar*) NULL);
|
||||
|
||||
irem= (struct st_irem *) (((char*) ptr) - ALIGN_SIZE(sizeof(struct st_irem))-
|
||||
sf_malloc_prehunc);
|
||||
if (*((uint32*) (((char*) ptr)- sizeof(uint32))) != MAGICKEY)
|
||||
{
|
||||
fprintf(stderr, "Error: Reallocating unallocated data at line %d, '%s'\n",
|
||||
lineno, filename);
|
||||
DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
|
||||
lineno, filename));
|
||||
(void) fflush(stderr);
|
||||
DBUG_RETURN((uchar*) NULL);
|
||||
}
|
||||
|
||||
if ((data= _mymalloc(size,filename,lineno,MyFlags))) /* Allocate new area */
|
||||
{
|
||||
size=min(size, irem->datasize); /* Move as much as possibly */
|
||||
memcpy((uchar*) data, ptr, (size_t) size); /* Copy old data */
|
||||
_myfree(ptr, filename, lineno, 0); /* Free not needed area */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MyFlags & MY_HOLD_ON_ERROR)
|
||||
DBUG_RETURN(ptr);
|
||||
if (MyFlags & MY_FREE_ON_ERROR)
|
||||
_myfree(ptr, filename, lineno, 0);
|
||||
}
|
||||
DBUG_RETURN(data);
|
||||
} /* _myrealloc */
|
||||
|
||||
|
||||
/* Deallocate some memory. */
|
||||
|
||||
void _myfree(void *ptr, const char *filename, uint lineno, myf myflags)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
DBUG_ENTER("_myfree");
|
||||
DBUG_PRINT("enter",("ptr: %p", ptr));
|
||||
|
||||
if (!sf_malloc_quick)
|
||||
(void) _sanity (filename, lineno);
|
||||
|
||||
if ((!ptr && (myflags & MY_ALLOW_ZERO_PTR)) ||
|
||||
check_ptr("Freeing",(uchar*) ptr,filename,lineno))
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
/* Calculate the address of the remember structure */
|
||||
irem= (struct st_irem *) ((char*) ptr- ALIGN_SIZE(sizeof(struct st_irem))-
|
||||
sf_malloc_prehunc);
|
||||
|
||||
/*
|
||||
Check to make sure that we have a real remember structure.
|
||||
Note: this test could fail for four reasons:
|
||||
(1) The memory was already free'ed
|
||||
(2) The memory was never new'ed
|
||||
(3) There was an underrun
|
||||
(4) A stray pointer hit this location
|
||||
*/
|
||||
|
||||
if (*((uint32*) ((char*) ptr- sizeof(uint32))) != MAGICKEY)
|
||||
{
|
||||
fprintf(stderr, "Error: Freeing unallocated data at line %d, '%s'\n",
|
||||
lineno, filename);
|
||||
DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",lineno,filename));
|
||||
(void) fflush(stderr);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* Remove this structure from the linked list */
|
||||
pthread_mutex_lock(&THR_LOCK_malloc);
|
||||
if (irem->prev)
|
||||
irem->prev->next= irem->next;
|
||||
else
|
||||
sf_malloc_root= irem->next;
|
||||
|
||||
if (irem->next)
|
||||
irem->next->prev= irem->prev;
|
||||
/* Handle the statistics */
|
||||
sf_malloc_cur_memory-= irem->datasize;
|
||||
sf_malloc_count--;
|
||||
pthread_mutex_unlock(&THR_LOCK_malloc);
|
||||
|
||||
#ifndef HAVE_purify
|
||||
/* Mark this data as free'ed */
|
||||
if (!sf_malloc_quick)
|
||||
bfill(ptr, irem->datasize, (pchar) FREE_VAL);
|
||||
#endif
|
||||
MEM_NOACCESS(ptr, irem->datasize);
|
||||
*((uint32*) ((char*) ptr- sizeof(uint32)))= ~MAGICKEY;
|
||||
MEM_NOACCESS((char*) ptr - sizeof(uint32), sizeof(uint32));
|
||||
/* Actually free the memory */
|
||||
free((char*) irem);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* Check if we have a wrong pointer */
|
||||
|
||||
static int check_ptr(const char *where, uchar *ptr, const char *filename,
|
||||
uint lineno)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
fprintf(stderr, "Error: %s NULL pointer at line %d, '%s'\n",
|
||||
where,lineno, filename);
|
||||
DBUG_PRINT("safe",("Null pointer at line %d '%s'", lineno, filename));
|
||||
(void) fflush(stderr);
|
||||
return 1;
|
||||
}
|
||||
#ifndef _MSC_VER
|
||||
if ((long) ptr & (ALIGN_SIZE(1)-1))
|
||||
{
|
||||
fprintf(stderr, "Error: %s wrong aligned pointer at line %d, '%s'\n",
|
||||
where,lineno, filename);
|
||||
DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
|
||||
lineno,filename));
|
||||
(void) fflush(stderr);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if (ptr < sf_min_adress || ptr > sf_max_adress)
|
||||
{
|
||||
fprintf(stderr, "Error: %s pointer out of range at line %d, '%s'\n",
|
||||
where,lineno, filename);
|
||||
DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
|
||||
lineno,filename));
|
||||
(void) fflush(stderr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Report on all the memory pieces that have not been free'ed
|
||||
|
||||
SYNOPSIS
|
||||
TERMINATE()
|
||||
file Write output to this file
|
||||
flag If <> 0, also write statistics
|
||||
*/
|
||||
|
||||
void TERMINATE(FILE *file, uint flag)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
DBUG_ENTER("TERMINATE");
|
||||
pthread_mutex_lock(&THR_LOCK_malloc);
|
||||
|
||||
/*
|
||||
Report the difference between number of calls to
|
||||
NEW and the number of calls to FREE. >0 means more
|
||||
NEWs than FREEs. <0, etc.
|
||||
*/
|
||||
|
||||
if (sf_malloc_count)
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
fprintf(file, "Warning: Not freed memory segments: %u\n", sf_malloc_count);
|
||||
(void) fflush(file);
|
||||
}
|
||||
DBUG_PRINT("safe",("sf_malloc_count: %u", sf_malloc_count));
|
||||
}
|
||||
|
||||
/*
|
||||
Report on all the memory that was allocated with NEW
|
||||
but not free'ed with FREE.
|
||||
*/
|
||||
|
||||
if ((irem= sf_malloc_root))
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
fprintf(file, "Warning: Memory that was not free'ed (%lu bytes):\n",
|
||||
(ulong) sf_malloc_cur_memory);
|
||||
(void) fflush(file);
|
||||
}
|
||||
DBUG_PRINT("safe",("Memory that was not free'ed (%lu bytes):",
|
||||
(ulong) sf_malloc_cur_memory));
|
||||
while (irem)
|
||||
{
|
||||
char *data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
|
||||
sf_malloc_prehunc);
|
||||
if (file)
|
||||
{
|
||||
fprintf(file,
|
||||
"\t%6lu bytes at %p, allocated at line %4u in '%s'",
|
||||
(ulong) irem->datasize, data, irem->linenum, irem->filename);
|
||||
fprintf(file, "\n");
|
||||
(void) fflush(file);
|
||||
}
|
||||
DBUG_PRINT("safe",
|
||||
("%6lu bytes at %p, allocated at line %4d in '%s'",
|
||||
(ulong) irem->datasize,
|
||||
data, irem->linenum, irem->filename));
|
||||
irem= irem->next;
|
||||
}
|
||||
}
|
||||
/* Report the memory usage statistics */
|
||||
if (file && flag)
|
||||
{
|
||||
fprintf(file, "Maximum memory usage: %lu bytes (%luk)\n",
|
||||
(ulong) sf_malloc_max_memory,
|
||||
(ulong) (sf_malloc_max_memory + 1023L) / 1024L);
|
||||
(void) fflush(file);
|
||||
}
|
||||
DBUG_PRINT("safe",("Maximum memory usage: %lu bytes (%luk)",
|
||||
(ulong) sf_malloc_max_memory,
|
||||
(ulong) (sf_malloc_max_memory + 1023L) /1024L));
|
||||
pthread_mutex_unlock(&THR_LOCK_malloc);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Report where a piece of memory was allocated
|
||||
|
||||
This is usefull to call from withing a debugger
|
||||
*/
|
||||
|
||||
|
||||
void sf_malloc_report_allocated(void *memory)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
for (irem= sf_malloc_root ; irem ; irem=irem->next)
|
||||
{
|
||||
char *data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
|
||||
sf_malloc_prehunc);
|
||||
if (data <= (char*) memory && (char*) memory <= data + irem->datasize)
|
||||
{
|
||||
printf("%lu bytes at %p, allocated at line %u in '%s'\n",
|
||||
(ulong) irem->datasize, data, irem->linenum, irem->filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns 0 if chunk is ok */
|
||||
|
||||
static int _checkchunk(register struct st_irem *irem, const char *filename,
|
||||
uint lineno)
|
||||
{
|
||||
int flag=0;
|
||||
char *magicp, *data;
|
||||
|
||||
data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
|
||||
sf_malloc_prehunc);
|
||||
/* Check for a possible underrun */
|
||||
if (*((uint32*) (data- sizeof(uint32))) != MAGICKEY)
|
||||
{
|
||||
fprintf(stderr, "Error: Memory allocated at %s:%d was underrun,",
|
||||
irem->filename, irem->linenum);
|
||||
fprintf(stderr, " discovered at %s:%d\n", filename, lineno);
|
||||
(void) fflush(stderr);
|
||||
DBUG_PRINT("safe",("Underrun at %p, allocated at %s:%d",
|
||||
data, irem->filename, irem->linenum));
|
||||
flag=1;
|
||||
}
|
||||
|
||||
/* Check for a possible overrun */
|
||||
magicp= data + irem->datasize;
|
||||
if (*magicp++ != MAGICEND0 ||
|
||||
*magicp++ != MAGICEND1 ||
|
||||
*magicp++ != MAGICEND2 ||
|
||||
*magicp++ != MAGICEND3)
|
||||
{
|
||||
fprintf(stderr, "Error: Memory allocated at %s:%d was overrun,",
|
||||
irem->filename, irem->linenum);
|
||||
fprintf(stderr, " discovered at '%s:%d'\n", filename, lineno);
|
||||
(void) fflush(stderr);
|
||||
DBUG_PRINT("safe",("Overrun at %p, allocated at %s:%d",
|
||||
data, irem->filename, irem->linenum));
|
||||
flag=1;
|
||||
}
|
||||
return(flag);
|
||||
}
|
||||
|
||||
|
||||
/* Returns how many wrong chunks */
|
||||
|
||||
int _sanity(const char *filename, uint lineno)
|
||||
{
|
||||
reg1 struct st_irem *irem;
|
||||
reg2 int flag=0;
|
||||
uint count=0;
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_malloc);
|
||||
#ifndef PEDANTIC_SAFEMALLOC
|
||||
if (sf_malloc_tampered && (int) sf_malloc_count < 0)
|
||||
sf_malloc_count=0;
|
||||
#endif
|
||||
count=sf_malloc_count;
|
||||
for (irem= sf_malloc_root; irem != NULL && count-- ; irem= irem->next)
|
||||
flag+= _checkchunk (irem, filename, lineno);
|
||||
pthread_mutex_unlock(&THR_LOCK_malloc);
|
||||
if (count || irem)
|
||||
{
|
||||
const char *format="Error: Safemalloc link list destroyed, discovered at '%s:%d'";
|
||||
fprintf(stderr, format, filename, lineno); fputc('\n',stderr);
|
||||
fprintf(stderr, "root=%p,count=%d,irem=%p\n", sf_malloc_root,count,irem);
|
||||
(void) fflush(stderr);
|
||||
DBUG_PRINT("safe",(format, filename, lineno));
|
||||
flag=1;
|
||||
}
|
||||
return flag;
|
||||
} /* _sanity */
|
||||
|
||||
|
||||
/* malloc and copy */
|
||||
|
||||
void *_my_memdup(const void *from, size_t length, const char *filename,
|
||||
uint lineno, myf MyFlags)
|
||||
{
|
||||
void *ptr;
|
||||
if ((ptr= _mymalloc(length,filename,lineno,MyFlags)) != 0)
|
||||
memcpy(ptr, from, length);
|
||||
return(ptr);
|
||||
} /*_my_memdup */
|
||||
|
||||
|
||||
char *_my_strdup(const char *from, const char *filename, uint lineno,
|
||||
myf MyFlags)
|
||||
{
|
||||
char *ptr;
|
||||
size_t length= strlen(from)+1;
|
||||
if ((ptr= (char*) _mymalloc(length,filename,lineno,MyFlags)) != 0)
|
||||
memcpy((uchar*) ptr, (uchar*) from, (size_t) length);
|
||||
return(ptr);
|
||||
} /* _my_strdup */
|
||||
|
||||
|
||||
char *_my_strndup(const char *from, size_t length,
|
||||
const char *filename, uint lineno,
|
||||
myf MyFlags)
|
||||
{
|
||||
char *ptr;
|
||||
if ((ptr= (char*) _mymalloc(length+1,filename,lineno,MyFlags)) != 0)
|
||||
{
|
||||
memcpy((uchar*) ptr, (uchar*) from, (size_t) length);
|
||||
ptr[length]=0;
|
||||
}
|
||||
return(ptr);
|
||||
}
|
||||
+43
-12
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2002, 2004, 2006 MySQL AB
|
||||
/* Copyright (c) 2002, 2004, 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -6,26 +6,57 @@
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
Original Source from: http://www.faqs.org/rfcs/rfc3174.html
|
||||
|
||||
DESCRIPTION
|
||||
This file implements the Secure Hashing Algorithm 1 as
|
||||
defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
Copyright (C) The Internet Society (2001). All Rights Reserved.
|
||||
|
||||
The SHA-1, produces a 160-bit message digest for a given data
|
||||
stream. It should take about 2**n steps to find a message with the
|
||||
same digest as a given message and 2**(n/2) to find any two
|
||||
messages with the same digest, when n is the digest size in bits.
|
||||
Therefore, this algorithm can serve as a means of providing a
|
||||
"fingerprint" for a message.
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Acknowledgement
|
||||
Funding for the RFC Editor function is currently provided by the
|
||||
Internet Society.
|
||||
|
||||
DESCRIPTION
|
||||
This file implements the Secure Hashing Algorithm 1 as
|
||||
defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
|
||||
The SHA-1, produces a 160-bit message digest for a given data
|
||||
stream. It should take about 2**n steps to find a message with the
|
||||
same digest as a given message and 2**(n/2) to find any two
|
||||
messages with the same digest, when n is the digest size in bits.
|
||||
Therefore, this algorithm can serve as a means of providing a
|
||||
"fingerprint" for a message.
|
||||
|
||||
PORTABILITY ISSUES
|
||||
SHA-1 is defined in terms of 32-bit "words". This code uses
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user