summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
Diffstat (limited to 'mysys')
-rwxr-xr-xmysys/CMakeLists.txt13
-rw-r--r--mysys/Makefile.am29
-rw-r--r--mysys/array.c141
-rw-r--r--mysys/base64.c68
-rw-r--r--mysys/charset-def.c1
-rw-r--r--mysys/charset.c92
-rw-r--r--mysys/checksum.c9
-rw-r--r--mysys/default.c49
-rw-r--r--mysys/default_modify.c61
-rw-r--r--mysys/errors.c6
-rw-r--r--mysys/hash.c105
-rw-r--r--mysys/list.c6
-rwxr-xr-xmysys/make-ccc2
-rw-r--r--mysys/mf_cache.c2
-rw-r--r--mysys/mf_dirname.c33
-rw-r--r--mysys/mf_fn_ext.c11
-rw-r--r--mysys/mf_format.c39
-rw-r--r--mysys/mf_getdate.c4
-rw-r--r--mysys/mf_iocache.c253
-rw-r--r--mysys/mf_iocache2.c198
-rw-r--r--mysys/mf_keycache.c2650
-rw-r--r--mysys/mf_keycaches.c44
-rw-r--r--mysys/mf_loadpath.c4
-rw-r--r--mysys/mf_pack.c211
-rw-r--r--mysys/mf_path.c16
-rw-r--r--mysys/mf_radix.c4
-rw-r--r--mysys/mf_same.c5
-rw-r--r--mysys/mf_sort.c8
-rw-r--r--mysys/mf_soundex.c4
-rw-r--r--mysys/mf_strip.c12
-rw-r--r--mysys/mf_tempdir.c30
-rw-r--r--mysys/mf_unixpath.c2
-rw-r--r--mysys/mf_wfile.c14
-rw-r--r--mysys/mulalloc.c6
-rw-r--r--mysys/my_access.c106
-rw-r--r--mysys/my_alloc.c65
-rw-r--r--mysys/my_append.c16
-rw-r--r--mysys/my_atomic.c46
-rw-r--r--mysys/my_bit.c30
-rw-r--r--mysys/my_bitmap.c1038
-rw-r--r--mysys/my_chsize.c8
-rw-r--r--mysys/my_clock.c5
-rw-r--r--mysys/my_compress.c204
-rw-r--r--mysys/my_conio.c17
-rw-r--r--mysys/my_copy.c9
-rw-r--r--mysys/my_create.c18
-rw-r--r--mysys/my_div.c2
-rw-r--r--mysys/my_dup.c3
-rw-r--r--mysys/my_error.c20
-rw-r--r--mysys/my_file.c30
-rw-r--r--mysys/my_fopen.c5
-rw-r--r--mysys/my_fstream.c92
-rw-r--r--mysys/my_gethostbyname.c2
-rw-r--r--mysys/my_gethwaddr.c2
-rw-r--r--mysys/my_getncpus.c39
-rw-r--r--mysys/my_getopt.c164
-rw-r--r--mysys/my_getsystime.c200
-rw-r--r--mysys/my_getwd.c85
-rw-r--r--mysys/my_init.c66
-rw-r--r--mysys/my_largepage.c26
-rw-r--r--mysys/my_lib.c143
-rw-r--r--mysys/my_lock.c10
-rw-r--r--mysys/my_lockmem.c18
-rw-r--r--mysys/my_lread.c54
-rw-r--r--mysys/my_lwrite.c47
-rw-r--r--mysys/my_malloc.c38
-rw-r--r--mysys/my_memmem.c3
-rw-r--r--mysys/my_mkdir.c2
-rw-r--r--mysys/my_mmap.c5
-rw-r--r--mysys/my_net.c4
-rw-r--r--mysys/my_once.c28
-rw-r--r--mysys/my_open.c47
-rw-r--r--mysys/my_os2cond.c162
-rw-r--r--mysys/my_os2dirsrch.c184
-rw-r--r--mysys/my_os2dirsrch.h88
-rw-r--r--mysys/my_os2dlfcn.c74
-rw-r--r--mysys/my_os2dlfcn.h039
-rw-r--r--mysys/my_os2file64.c394
-rw-r--r--mysys/my_os2mutex.c83
-rw-r--r--mysys/my_os2thread.c128
-rw-r--r--mysys/my_os2tls.c151
-rw-r--r--mysys/my_pread.c106
-rw-r--r--mysys/my_pthread.c11
-rw-r--r--mysys/my_quick.c18
-rw-r--r--mysys/my_read.c25
-rw-r--r--mysys/my_realloc.c10
-rw-r--r--mysys/my_redel.c5
-rw-r--r--mysys/my_rename.c1
-rw-r--r--mysys/my_seek.c2
-rw-r--r--mysys/my_sleep.c2
-rw-r--r--mysys/my_static.c24
-rw-r--r--mysys/my_static.h4
-rw-r--r--mysys/my_symlink2.c4
-rw-r--r--mysys/my_thr_init.c53
-rw-r--r--mysys/my_vle.c109
-rw-r--r--mysys/my_wincond.c2
-rw-r--r--mysys/my_windac.c8
-rw-r--r--mysys/my_write.c26
-rw-r--r--mysys/mysys_priv.h4
-rw-r--r--mysys/ptr_cmp.c28
-rw-r--r--mysys/queues.c485
-rw-r--r--mysys/raid.cc798
-rw-r--r--mysys/raid2.c31
-rw-r--r--mysys/safemalloc.c90
-rw-r--r--mysys/string.c44
-rw-r--r--mysys/test_dir.c1
-rw-r--r--mysys/testhash.c8
-rw-r--r--mysys/thr_alarm.c241
-rw-r--r--mysys/thr_lock.c261
-rw-r--r--mysys/thr_mutex.c81
-rw-r--r--mysys/tree.c8
-rw-r--r--mysys/trie.c236
-rw-r--r--mysys/typelib.c84
113 files changed, 6470 insertions, 4472 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 8aaf0b5f00f..9fb9a47dad3 100755
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -19,6 +19,14 @@ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
# executables all link with recompiles of source found in the "mysys" directory.
# So we only need to create one version of this library, with the "static"
# Thread Local Storage model.
+#
+# Exception is the embedded server that needs this library compiled with
+# dynamic TLS, i.e. define USE_TLS
+
+IF(EMBEDDED_ONLY)
+ ADD_DEFINITIONS(-DUSE_TLS)
+ ADD_DEFINITIONS(-DEMBEDDED_LIBRARY)
+ENDIF(EMBEDDED_ONLY)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys)
@@ -32,11 +40,10 @@ ADD_LIBRARY(mysys array.c charset-def.c charset.c checksum.c default.c default_m
my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c
my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c
my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c
- my_lib.c my_lock.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c
+ my_lib.c my_lock.c my_lockmem.c my_malloc.c my_messnc.c
my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c
my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
- thr_rwlock.c tree.c typelib.c base64.c my_memmem.c
- my_getpagesize.c)
+ thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c)
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index a835492e670..fca13ab52b8 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -19,12 +19,8 @@ MYSQLBASEdir= $(prefix)
INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
-LDADD = libmysys.a ../dbug/libdbug.a \
- ../strings/libmystrings.a
-noinst_HEADERS = mysys_priv.h my_static.h \
- my_os2cond.c my_os2dirsrch.c my_os2dirsrch.h \
- my_os2dlfcn.c my_os2file64.c my_os2mutex.c \
- my_os2thread.c my_os2tls.c
+LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a
+noinst_HEADERS = mysys_priv.h my_static.h
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
@@ -34,6 +30,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
my_alloc.c safemalloc.c my_new.cc \
+ my_vle.c my_atomic.c \
my_fopen.c my_fstream.c my_getsystime.c \
my_error.c errors.c my_div.c my_messnc.c \
mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
@@ -41,15 +38,15 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_pack.c mf_unixpath.c mf_strip.c \
mf_wcomp.c mf_wfile.c my_gethwaddr.c \
mf_qsort.c mf_qsort2.c mf_sort.c \
- ptr_cmp.c mf_radix.c queues.c \
- tree.c list.c hash.c array.c string.c typelib.c \
+ ptr_cmp.c mf_radix.c queues.c my_getncpus.c \
+ tree.c trie.c list.c hash.c array.c string.c typelib.c \
my_copy.c my_append.c my_lib.c \
my_delete.c my_rename.c my_redel.c \
- my_chsize.c my_lread.c my_lwrite.c my_clock.c \
+ my_chsize.c my_clock.c \
my_quick.c my_lockmem.c my_static.c \
my_sync.c my_getopt.c my_mkdir.c \
default_modify.c default.c \
- my_compress.c checksum.c raid.cc \
+ my_compress.c checksum.c \
my_net.c my_port.c my_sleep.c \
charset.c charset-def.c my_bitmap.c my_bit.c md5.c \
my_gethostbyname.c rijndael.c my_aes.c sha1.c \
@@ -57,14 +54,14 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
my_memmem.c \
my_windac.c my_access.c base64.c my_libwrap.c
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
- thr_mutex.c thr_rwlock.c mf_soundex.c my_conio.c \
- my_wincond.c my_winthread.c CMakeLists.txt
+ thr_mutex.c thr_rwlock.c \
+ CMakeLists.txt mf_soundex.c \
+ my_conio.c my_wincond.c my_winthread.c
libmysys_a_LIBADD = @THREAD_LOBJECTS@
# test_dir_DEPENDENCIES= $(LIBRARIES)
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
# charset2html_DEPENDENCIES= $(LIBRARIES)
-EXTRA_PROGRAMS =
DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
@@ -84,6 +81,12 @@ FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) @NOINST_LDFLAGS@
# which automaticly removes the object files you use to compile a final program
#
+test_bitmap$(EXEEXT): my_bitmap.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN ./my_bitmap.c $(LDADD) $(LIBS)
+
+test_priority_queue$(EXEEXT): queues.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN ./queues.c $(LDADD) $(LIBS)
+
test_thr_alarm$(EXEEXT): thr_alarm.c $(LIBRARIES)
$(CP) $(srcdir)/thr_alarm.c ./test_thr_alarm.c
$(LINK) $(FLAGS) -DMAIN ./test_thr_alarm.c $(LDADD) $(LIBS)
diff --git a/mysys/array.c b/mysys/array.c
index 4ea1946d837..8a539f18a20 100644
--- a/mysys/array.c
+++ b/mysys/array.c
@@ -22,9 +22,10 @@
Initiate dynamic array
SYNOPSIS
- init_dynamic_array()
+ init_dynamic_array2()
array Pointer to an array
element_size Size of element
+ init_buffer Initial buffer pointer
init_alloc Number of initial elements
alloc_increment Increment for adding new elements
@@ -32,15 +33,16 @@
init_dynamic_array() initiates array and allocate space for
init_alloc eilements.
Array is usable even if space allocation failed.
+ Static buffers must begin immediately after the array structure.
RETURN VALUE
TRUE my_malloc_ci() failed
FALSE Ok
*/
-my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
- uint init_alloc,
- uint alloc_increment CALLER_INFO_PROTO)
+my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
+ void *init_buffer, uint init_alloc,
+ uint alloc_increment CALLER_INFO_PROTO)
{
DBUG_ENTER("init_dynamic_array");
if (!alloc_increment)
@@ -51,12 +53,17 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
}
if (!init_alloc)
+ {
init_alloc=alloc_increment;
+ init_buffer= 0;
+ }
array->elements=0;
array->max_element=init_alloc;
array->alloc_increment=alloc_increment;
array->size_of_element=element_size;
- if (!(array->buffer=(char*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
+ if ((array->buffer= init_buffer))
+ DBUG_RETURN(FALSE);
+ if (!(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
{
array->max_element=0;
DBUG_RETURN(TRUE);
@@ -64,6 +71,14 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
DBUG_RETURN(FALSE);
}
+my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
+ uint init_alloc,
+ uint alloc_increment CALLER_INFO_PROTO)
+{
+ /* placeholder to preserve ABI */
+ return my_init_dynamic_array_ci(array, element_size, init_alloc,
+ alloc_increment);
+}
/*
Insert element at the end of array. Allocate memory if needed.
@@ -77,9 +92,9 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
FALSE Ok
*/
-my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
+my_bool insert_dynamic(DYNAMIC_ARRAY *array, uchar* element)
{
- gptr buffer;
+ uchar* buffer;
if (array->elements == array->max_element)
{ /* Call only when nessesary */
if (!(buffer=alloc_dynamic(array)))
@@ -112,17 +127,32 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
0 Error
*/
-byte *alloc_dynamic(DYNAMIC_ARRAY *array)
+uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
{
if (array->elements == array->max_element)
{
char *new_ptr;
+ if (array->buffer == (uchar *)(array + 1))
+ {
+ /*
+ In this senerio, the buffer is statically preallocated,
+ so we have to create an all-new malloc since we overflowed
+ */
+ if (!(new_ptr= (char *) my_malloc((array->max_element+
+ array->alloc_increment) *
+ array->size_of_element,
+ MYF(MY_WME))))
+ return 0;
+ memcpy(new_ptr, array->buffer,
+ array->elements * array->size_of_element);
+ }
+ else
if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
- array->alloc_increment)*
- array->size_of_element,
- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ array->alloc_increment)*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
return 0;
- array->buffer=new_ptr;
+ array->buffer= (uchar*) new_ptr;
array->max_element+=array->alloc_increment;
}
return array->buffer+(array->elements++ * array->size_of_element);
@@ -141,7 +171,7 @@ byte *alloc_dynamic(DYNAMIC_ARRAY *array)
0 Array is empty
*/
-byte *pop_dynamic(DYNAMIC_ARRAY *array)
+uchar *pop_dynamic(DYNAMIC_ARRAY *array)
{
if (array->elements)
return array->buffer+(--array->elements * array->size_of_element);
@@ -166,7 +196,7 @@ byte *pop_dynamic(DYNAMIC_ARRAY *array)
FALSE Ok
*/
-my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+my_bool set_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
{
if (idx >= array->elements)
{
@@ -176,19 +206,33 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
char *new_ptr;
size=(idx+array->alloc_increment)/array->alloc_increment;
size*= array->alloc_increment;
+ if (array->buffer == (uchar *)(array + 1))
+ {
+ /*
+ In this senerio, the buffer is statically preallocated,
+ so we have to create an all-new malloc since we overflowed
+ */
+ if (!(new_ptr= (char *) my_malloc(size *
+ array->size_of_element,
+ MYF(MY_WME))))
+ return 0;
+ memcpy(new_ptr, array->buffer,
+ array->elements * array->size_of_element);
+ }
+ else
if (!(new_ptr=(char*) my_realloc(array->buffer,size*
- array->size_of_element,
- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
return TRUE;
- array->buffer=new_ptr;
+ array->buffer= (uchar*) new_ptr;
array->max_element=size;
}
- bzero((gptr) (array->buffer+array->elements*array->size_of_element),
- (idx - array->elements)*array->size_of_element);
+ bzero((uchar*) (array->buffer+array->elements*array->size_of_element),
+ (idx - array->elements)*array->size_of_element);
array->elements=idx+1;
}
memcpy(array->buffer+(idx * array->size_of_element),element,
- (size_t) array->size_of_element);
+ (size_t) array->size_of_element);
return FALSE;
}
@@ -198,21 +242,21 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
SYNOPSIS
get_dynamic()
array
- gptr Element to be returned. If idx > elements contain zeroes.
+ uchar* Element to be returned. If idx > elements contain zeroes.
idx Index of element wanted.
*/
-void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+void get_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
{
if (idx >= array->elements)
{
DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
- idx,array->elements));
+ idx,array->elements));
bzero(element,array->size_of_element);
return;
}
memcpy(element,array->buffer+idx*array->size_of_element,
- (size_t) array->size_of_element);
+ (size_t) array->size_of_element);
}
@@ -226,6 +270,12 @@ void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
void delete_dynamic(DYNAMIC_ARRAY *array)
{
+ /*
+ Just mark as empty if we are using a static buffer
+ */
+ if (array->buffer == (uchar *)(array + 1))
+ array->elements= 0;
+ else
if (array->buffer)
{
my_free(array->buffer,MYF(MY_WME));
@@ -240,15 +290,15 @@ void delete_dynamic(DYNAMIC_ARRAY *array)
SYNOPSIS
delete_dynamic_element()
array
- idx Index of element to be deleted
+ idx Index of element to be deleted
*/
void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
{
- char *ptr=array->buffer+array->size_of_element*idx;
+ char *ptr= (char*) array->buffer+array->size_of_element*idx;
array->elements--;
memmove(ptr,ptr+array->size_of_element,
- (array->elements-idx)*array->size_of_element);
+ (array->elements-idx)*array->size_of_element);
}
@@ -265,11 +315,42 @@ void freeze_size(DYNAMIC_ARRAY *array)
{
uint elements=max(array->elements,1);
+ /*
+ Do nothing if we are using a static buffer
+ */
+ if (array->buffer == (uchar *)(array + 1))
+ return;
+
if (array->buffer && array->max_element != elements)
{
- array->buffer=(char*) my_realloc(array->buffer,
- elements*array->size_of_element,
- MYF(MY_WME));
+ array->buffer=(uchar*) my_realloc(array->buffer,
+ elements*array->size_of_element,
+ MYF(MY_WME));
array->max_element=elements;
}
}
+
+
+/*
+ Get the index of a dynamic element
+
+ SYNOPSIS
+ get_index_dynamic()
+ array Array
+ element Whose element index
+
+*/
+
+int get_index_dynamic(DYNAMIC_ARRAY *array, uchar* element)
+{
+ uint ret;
+ if (array->buffer > element)
+ return -1;
+
+ ret= (element - array->buffer) / array->size_of_element;
+ if (ret > array->elements)
+ return -1;
+
+ return ret;
+
+}
diff --git a/mysys/base64.c b/mysys/base64.c
index 47b93942784..dbe8927290d 100644
--- a/mysys/base64.c
+++ b/mysys/base64.c
@@ -13,8 +13,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <base64.h>
+#include <my_global.h>
#include <m_string.h> /* strchr() */
+#include <m_ctype.h> /* my_isspace() */
+#include <base64.h>
#ifndef MAIN
@@ -114,7 +116,6 @@ pos(unsigned char c)
} \
if (i == size) \
{ \
- i= size + 1; \
break; \
} \
}
@@ -123,44 +124,69 @@ pos(unsigned char c)
/*
Decode a base64 string
- Note: We require that dst is pre-allocated to correct size.
- See base64_needed_decoded_length().
+ 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.
- RETURN Number of bytes produced in dst or -1 in case of failure
+ 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, size_t size, void *dst)
+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 < size)
+ while (i < len)
{
unsigned c= 0;
size_t mark= 0;
- SKIP_SPACE(src, i, size);
+ SKIP_SPACE(src, i, len);
c += pos(*src++);
c <<= 6;
i++;
- SKIP_SPACE(src, i, size);
+ SKIP_SPACE(src, i, len);
c += pos(*src++);
c <<= 6;
i++;
- SKIP_SPACE(src, i, size);
+ SKIP_SPACE(src, i, len);
- if (* src != '=')
+ if (*src != '=')
c += pos(*src++);
else
{
- i= size;
+ src += 2; /* There should be two bytes padding */
+ i= len;
mark= 2;
c <<= 6;
goto end;
@@ -168,13 +194,14 @@ base64_decode(const char *src, size_t size, void *dst)
c <<= 6;
i++;
- SKIP_SPACE(src, i, size);
+ SKIP_SPACE(src, i, len);
if (*src != '=')
c += pos(*src++);
else
{
- i= size;
+ src += 1; /* There should be one byte padding */
+ i= len;
mark= 1;
goto end;
}
@@ -189,11 +216,14 @@ base64_decode(const char *src, size_t size, void *dst)
*d++= b[j];
}
- if (i != size)
- {
- return -1;
- }
- return d - dst_base;
+ 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 : d - dst_base;
}
diff --git a/mysys/charset-def.c b/mysys/charset-def.c
index 36ff4139d9c..63bbceef29b 100644
--- a/mysys/charset-def.c
+++ b/mysys/charset-def.c
@@ -75,6 +75,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
CHARSET_INFO *cs;
add_compiled_collation(&my_charset_bin);
+ add_compiled_collation(&my_charset_filename);
add_compiled_collation(&my_charset_latin1);
add_compiled_collation(&my_charset_latin1_bin);
diff --git a/mysys/charset.c b/mysys/charset.c
index 4c3f2d0ab71..692d7867fe0 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -326,14 +326,14 @@ static int charset_initialized=0;
static my_bool my_read_charset_file(const char *filename, myf myflags)
{
- char *buf;
+ uchar *buf;
int fd;
uint len, tmp_len;
MY_STAT stat_info;
if (!my_stat(filename, &stat_info, MYF(myflags)) ||
((len= (uint)stat_info.st_size) > MY_MAX_ALLOWED_BUF) ||
- !(buf= (char *)my_malloc(len,myflags)))
+ !(buf= (uchar*) my_malloc(len,myflags)))
return TRUE;
if ((fd=my_open(filename,O_RDONLY,myflags)) < 0)
@@ -343,7 +343,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags)
if (tmp_len != len)
goto error;
- if (my_parse_charset_xml(buf,len,add_collation))
+ if (my_parse_charset_xml((char*) buf,len,add_collation))
{
#ifdef NOT_YET
printf("ERROR at line %d pos %d '%s'\n",
@@ -353,7 +353,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags)
#endif
}
- my_free(buf, myflags);
+ my_free(buf, myflags);
return FALSE;
error:
@@ -393,7 +393,7 @@ void add_compiled_collation(CHARSET_INFO *cs)
cs->state|= MY_CS_AVAILABLE;
}
-static void *cs_alloc(uint size)
+static void *cs_alloc(size_t size)
{
return my_once_alloc(size, MYF(MY_WME));
}
@@ -590,6 +590,70 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
}
+/**
+ Resolve character set by the character set name (utf8, latin1, ...).
+
+ The function tries to resolve character set by the specified name. If
+ there is character set with the given name, it is assigned to the "cs"
+ parameter and FALSE is returned. If there is no such character set,
+ "default_cs" is assigned to the "cs" and TRUE is returned.
+
+ @param[in] cs_name Character set name.
+ @param[in] default_cs Default character set.
+ @param[out] cs Variable to store character set.
+
+ @return FALSE if character set was resolved successfully; TRUE if there
+ is no character set with given name.
+*/
+
+bool resolve_charset(const char *cs_name,
+ CHARSET_INFO *default_cs,
+ CHARSET_INFO **cs)
+{
+ *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
+
+ if (*cs == NULL)
+ {
+ *cs= default_cs;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Resolve collation by the collation name (utf8_general_ci, ...).
+
+ The function tries to resolve collation by the specified name. If there
+ is collation with the given name, it is assigned to the "cl" parameter
+ and FALSE is returned. If there is no such collation, "default_cl" is
+ assigned to the "cl" and TRUE is returned.
+
+ @param[out] cl Variable to store collation.
+ @param[in] cl_name Collation name.
+ @param[in] default_cl Default collation.
+
+ @return FALSE if collation was resolved successfully; TRUE if there is no
+ collation with given name.
+*/
+
+bool resolve_collation(const char *cl_name,
+ CHARSET_INFO *default_cl,
+ CHARSET_INFO **cl)
+{
+ *cl= get_charset_by_name(cl_name, MYF(0));
+
+ if (*cl == NULL)
+ {
+ *cl= default_cl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/*
Escape string with backslashes (\)
@@ -611,13 +675,13 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
"big enough"
RETURN VALUES
- ~0 The escaped string did not fit in the to buffer
- >=0 The length of the escaped string
+ (size_t) -1 The escaped string did not fit in the to buffer
+ # The length of the escaped string
*/
-ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
- char *to, ulong to_length,
- const char *from, ulong length)
+size_t escape_string_for_mysql(CHARSET_INFO *charset_info,
+ char *to, size_t to_length,
+ const char *from, size_t length)
{
const char *to_start= to;
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
@@ -701,7 +765,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info,
}
}
*to= 0;
- return overflow ? (ulong)~0 : (ulong) (to - to_start);
+ return overflow ? (size_t) -1 : (size_t) (to - to_start);
}
@@ -755,9 +819,9 @@ CHARSET_INFO *fs_character_set()
>=0 The length of the escaped string
*/
-ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info,
- char *to, ulong to_length,
- const char *from, ulong length)
+size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
+ char *to, size_t to_length,
+ const char *from, size_t length)
{
const char *to_start= to;
const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
diff --git a/mysys/checksum.c b/mysys/checksum.c
index 09e9c5b3730..4f86f6845f0 100644
--- a/mysys/checksum.c
+++ b/mysys/checksum.c
@@ -15,7 +15,8 @@
#include <my_global.h>
-#include "my_sys.h"
+#include <my_sys.h>
+#include <zlib.h>
/*
Calculate a long checksum for a memoryblock.
@@ -27,15 +28,15 @@
length length of the block
*/
-ha_checksum my_checksum(ha_checksum crc, const byte *pos, uint length)
+ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length)
{
#ifdef NOT_USED
- const byte *end=pos+length;
+ const uchar *end=pos+length;
for ( ; pos != end ; pos++)
crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8));
return crc;
#else
- return (ha_checksum)crc32((uint)crc, (const uchar *)pos, length);
+ return (ha_checksum)crc32((uint)crc, pos, length);
#endif
}
diff --git a/mysys/default.c b/mysys/default.c
index aff38b6af0b..3cc5b08e77c 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -243,7 +243,8 @@ err:
handle_option_ctx structure.
group_name The name of the group the option belongs to.
option The very option to be processed. It is already
- prepared to be used in argv (has -- prefix)
+ prepared to be used in argv (has -- prefix). If it
+ is NULL, we are handling a new group (section).
DESCRIPTION
This handler checks whether a group is one of the listed and adds an option
@@ -262,11 +263,14 @@ static int handle_default_option(void *in_ctx, const char *group_name,
char *tmp;
struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
+ if (!option)
+ return 0;
+
if (find_type((char *)group_name, ctx->group, 3))
{
- if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1)))
+ if (!(tmp= alloc_root(ctx->alloc, strlen(option) + 1)))
return 1;
- if (insert_dynamic(ctx->args, (gptr) &tmp))
+ if (insert_dynamic(ctx->args, (uchar*) &tmp))
return 1;
strmov(tmp, option);
}
@@ -422,7 +426,7 @@ int load_defaults(const char *conf_file, const char **groups,
/* copy name + found arguments + command line arguments to new array */
res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
- memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
+ memcpy((uchar*) (res+1), args.buffer, args.elements*sizeof(char*));
/* Skip --defaults-xxx options */
(*argc)-= args_used;
(*argv)+= args_used;
@@ -438,7 +442,7 @@ int load_defaults(const char *conf_file, const char **groups,
}
if (*argc)
- memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
+ memcpy((uchar*) (res+1+args.elements), (char*) ((*argv)+1),
(*argc-1)*sizeof(char*));
res[args.elements+ *argc]=0; /* last null */
@@ -510,7 +514,7 @@ static int search_default_file(Process_option_func opt_handler,
# Returns pointer to the argument after the keyword.
*/
-static char *get_argument(const char *keyword, uint kwlen,
+static char *get_argument(const char *keyword, size_t kwlen,
char *ptr, char *name, uint line)
{
char *end;
@@ -600,7 +604,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(OS2) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
{
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(0)))
@@ -714,10 +718,15 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
name,line);
goto err;
}
- for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;/* Remove end space */
+ /* Remove end space */
+ for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
end[0]=0;
- strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096));
+ strmake(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
+
+ /* signal that a new group is found */
+ opt_handler(handler_ctx, curr_gr, NULL);
+
continue;
}
if (!found_group)
@@ -735,7 +744,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
if (!value)
{
- strmake(strmov(option,"--"),ptr,(uint) (end-ptr));
+ strmake(strmov(option,"--"),ptr, (size_t) (end-ptr));
if (opt_handler(handler_ctx, curr_gr, option))
goto err;
}
@@ -761,7 +770,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
value++;
value_end--;
}
- ptr=strnmov(strmov(option,"--"),ptr,(uint) (end-ptr));
+ ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr));
*ptr++= '=';
for ( ; value != value_end; value++)
@@ -923,9 +932,9 @@ void print_defaults(const char *conf_file, const char **groups)
typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
-static uint my_get_system_windows_directory(char *buffer, uint size)
+static size_t my_get_system_windows_directory(char *buffer, size_t size)
{
- uint count;
+ size_t count;
GET_SYSTEM_WINDOWS_DIRECTORY
func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
GetProcAddress(GetModuleHandle("kernel32.dll"),
@@ -978,10 +987,11 @@ static uint my_get_system_windows_directory(char *buffer, uint size)
Everywhere else, this is:
1. /etc/
- 2. getenv(DEFAULT_HOME_ENV)
- 3. ""
- 4. "~/"
- 5. --sysconfdir=<path>
+ 2. /etc/mysql/
+ 3. getenv(DEFAULT_HOME_ENV)
+ 4. ""
+ 5. "~/"
+ 6. --sysconfdir=<path>
*/
@@ -1002,11 +1012,8 @@ static void init_default_directories()
#elif defined(__NETWARE__)
*ptr++= "sys:/etc/";
#else
-#if defined(__EMX__) || defined(OS2)
- if ((env= getenv("ETC")))
- *ptr++= env;
-#endif
*ptr++= "/etc/";
+ *ptr++= "/etc/mysql/";
#endif
if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
*ptr++= env;
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index be40d3b3660..78f6105b071 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -39,11 +39,13 @@ static char *add_option(char *dst, const char *option_value,
SYNOPSYS
modify_defaults_file()
file_location The location of configuration file to edit
- option option to look for
- option value The value of the option we would like to set
- section_name the name of the section
- remove_option This is true if we want to remove the option.
- False otherwise.
+ 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
@@ -66,7 +68,8 @@ int modify_defaults_file(const char *file_location, const char *option,
FILE *cnf_file;
MY_STAT file_stat;
char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
- uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size;
+ size_t opt_len= 0, optval_len= 0, sect_len;
+ uint nr_newlines= 0, buffer_size;
my_bool in_section= FALSE, opt_applied= 0;
uint reserve_extended;
uint new_opt_len;
@@ -80,8 +83,11 @@ int modify_defaults_file(const char *file_location, const char *option,
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
goto malloc_err;
- opt_len= (uint) strlen(option);
- optval_len= (uint) strlen(option_value);
+ if (option && option_value)
+ {
+ opt_len= strlen(option);
+ optval_len= strlen(option_value);
+ }
new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
@@ -103,7 +109,7 @@ int modify_defaults_file(const char *file_location, const char *option,
MYF(MY_WME))))
goto malloc_err;
- sect_len= (uint) strlen(section_name);
+ sect_len= strlen(section_name);
for (dst_ptr= file_buffer; fgets(linebuff, BUFF_SIZE, cnf_file); )
{
@@ -118,8 +124,8 @@ int modify_defaults_file(const char *file_location, const char *option,
continue;
}
- /* correct the option */
- if (in_section && !strncmp(src_ptr, option, opt_len) &&
+ /* 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'))
@@ -142,7 +148,12 @@ int modify_defaults_file(const char *file_location, const char *option,
}
else
{
- /* If going to new group and we have option to apply, do it now */
+ /*
+ 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);
@@ -152,7 +163,10 @@ int modify_defaults_file(const char *file_location, const char *option,
for (; nr_newlines; nr_newlines--)
dst_ptr= strmov(dst_ptr, NEWLINE);
- dst_ptr= strmov(dst_ptr, linebuff);
+
+ /* 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 == '[')
@@ -166,18 +180,31 @@ int modify_defaults_file(const char *file_location, const char *option,
{}
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. */
- if (!opt_applied && !remove_option && in_section)
+
+ /*
+ 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 (*(dst_ptr - 1) != '\n')
+ 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;
@@ -191,7 +218,7 @@ int modify_defaults_file(const char *file_location, const char *option,
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, file_buffer, (uint) (dst_ptr - file_buffer),
+ my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
MYF(MY_NABP)))
goto err;
}
diff --git a/mysys/errors.c b/mysys/errors.c
index 857de1325d4..889cf6d7fe3 100644
--- a/mysys/errors.c
+++ b/mysys/errors.c
@@ -38,7 +38,7 @@ const char * NEAR globerrs[GLOBERRS]=
"Can't get working dirctory (Errcode: %d)",
"Can't change dir to '%s' (Errcode: %d)",
"Warning: '%s' had %d links",
- "%d files and %d streams is left open\n",
+ "Warning: %d files and %d streams is left open\n",
"Disk is full writing '%s' (Errcode: %d). Waiting for someone to free space... Retry in %d secs",
"Can't create directory '%s' (Errcode: %d)",
"Character set '%s' is not a compiled character set and is not specified in the '%s' file",
@@ -49,6 +49,7 @@ const char * NEAR globerrs[GLOBERRS]=
"Can't sync file '%s' to disk (Errcode: %d)",
"Collation '%s' is not a compiled collation and is not specified in the '%s' file",
"File '%s' not found (Errcode: %d)",
+ "File '%s' (fileno: %d) was not closed"
};
void init_glob_errs(void)
@@ -77,7 +78,7 @@ void init_glob_errs()
EE(EE_GETWD) = "Can't get working dirctory (Errcode: %d)";
EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
- EE(EE_OPEN_WARNING) = "%d files and %d streams is left open\n";
+ EE(EE_OPEN_WARNING) = "Warning: %d files and %d streams is left open\n";
EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
EE(EE_UNKNOWN_CHARSET)= "Character set '%s' is not a compiled character set and is not specified in the %s file";
@@ -88,5 +89,6 @@ void init_glob_errs()
EE(EE_SYNC)= "Can't sync file '%s' to disk (Errcode: %d)";
EE(EE_UNKNOWN_COLLATION)= "Collation '%s' is not a compiled collation and is not specified in the %s file";
EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
+ EE(EE_FILE_NOT_CLOSED) = "File '%s' (fileno: %d) was not closed";
}
#endif
diff --git a/mysys/hash.c b/mysys/hash.c
index 9e8404248eb..4532b06b533 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -30,15 +30,15 @@
typedef struct st_hash_info {
uint next; /* index to next key */
- byte *data; /* data for current entry */
+ uchar *data; /* data for current entry */
} HASH_LINK;
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
-static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
- uint length);
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
+ size_t length);
-static uint calc_hash(const HASH *hash, const byte *key, uint length)
+static uint 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);
@@ -47,12 +47,12 @@ static uint calc_hash(const HASH *hash, const byte *key, uint length)
my_bool
_hash_init(HASH *hash,CHARSET_INFO *charset,
- uint size,uint key_offset,uint key_length,
+ ulong size, size_t key_offset, size_t key_length,
hash_get_key get_key,
void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
{
DBUG_ENTER("hash_init");
- DBUG_PRINT("enter",("hash: 0x%lx size: %d", (long) hash, size));
+ DBUG_PRINT("enter",("hash: 0x%lx size: %u", (long) hash, (uint) size));
hash->records=0;
if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0))
@@ -108,7 +108,7 @@ static inline void hash_free_elements(HASH *hash)
void hash_free(HASH *hash)
{
DBUG_ENTER("hash_free");
- DBUG_PRINT("enter",("hash: 0x%lxd", (long) hash));
+ DBUG_PRINT("enter",("hash: 0x%lx", (long) hash));
hash_free_elements(hash);
hash->free= 0;
@@ -137,21 +137,21 @@ void my_hash_reset(HASH *hash)
DBUG_VOID_RETURN;
}
- /* some helper functions */
+/* some helper functions */
/*
- This function is char* instead of byte* as HPUX11 compiler can't
+ This function is char* instead of uchar* as HPUX11 compiler can't
handle inline functions that are not defined as native types
*/
static inline char*
-hash_key(const HASH *hash, const byte *record, uint *length,
+hash_key(const HASH *hash, const uchar *record, size_t *length,
my_bool first)
{
if (hash->get_key)
- return (*hash->get_key)(record,length,first);
+ return (char*) (*hash->get_key)(record,length,first);
*length=hash->key_length;
- return (byte*) record+hash->key_offset;
+ return (char*) record+hash->key_offset;
}
/* Calculate pos according to keys */
@@ -165,8 +165,8 @@ static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos,
uint buffmax, uint maxlength)
{
- uint length;
- byte *key= (byte*) hash_key(hash,pos->data,&length,0);
+ size_t length;
+ uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
}
@@ -177,15 +177,15 @@ static
#if !defined(__USLC__) && !defined(__sgi)
inline
#endif
-unsigned int rec_hashnr(HASH *hash,const byte *record)
+unsigned int rec_hashnr(HASH *hash,const uchar *record)
{
- uint length;
- byte *key= (byte*) hash_key(hash,record,&length,0);
+ size_t length;
+ uchar *key= (uchar*) hash_key(hash,record,&length,0);
return calc_hash(hash,key,length);
}
-gptr hash_search(const HASH *hash, const byte *key, uint length)
+uchar* hash_search(const HASH *hash, const uchar *key, size_t length)
{
HASH_SEARCH_STATE state;
return hash_first(hash, key, length, &state);
@@ -198,7 +198,7 @@ gptr hash_search(const HASH *hash, const byte *key, uint length)
Assigns the number of the found record to HASH_SEARCH_STATE state
*/
-gptr hash_first(const HASH *hash, const byte *key, uint length,
+uchar* hash_first(const HASH *hash, const uchar *key, size_t length,
HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
@@ -235,7 +235,7 @@ gptr hash_first(const HASH *hash, const byte *key, uint length,
/* Get next record with identical key */
/* Can only be called if previous calls was hash_search */
-gptr hash_next(const HASH *hash, const byte *key, uint length,
+uchar* hash_next(const HASH *hash, const uchar *key, size_t length,
HASH_SEARCH_STATE *current_record)
{
HASH_LINK *pos;
@@ -292,11 +292,11 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
!= 0 key of record != key
*/
-static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
- uint length)
+static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
+ size_t length)
{
- uint rec_keylength;
- byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1);
+ size_t rec_keylength;
+ uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
return ((length && length != rec_keylength) ||
my_strnncoll(hash->charset, (uchar*) rec_key, rec_keylength,
(uchar*) key, rec_keylength));
@@ -305,15 +305,25 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const byte *key,
/* Write a hash-key to the hash-index */
-my_bool my_hash_insert(HASH *info,const byte *record)
+my_bool my_hash_insert(HASH *info,const uchar *record)
{
int flag;
- uint halfbuff,hash_nr,first_index,idx;
- byte *ptr_to_rec,*ptr_to_rec2;
+ size_t idx;
+ uint halfbuff,hash_nr,first_index;
+ uchar *ptr_to_rec,*ptr_to_rec2;
HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
- LINT_INIT(gpos); LINT_INIT(gpos2);
- LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
+ LINT_INIT(gpos);
+ LINT_INIT(gpos2);
+ LINT_INIT(ptr_to_rec);
+ LINT_INIT(ptr_to_rec2);
+
+ if (HASH_UNIQUE & info->flags)
+ {
+ uchar *key= (uchar*) hash_key(info, record, &idx, 1);
+ if (hash_search(info, key, idx))
+ return(TRUE); /* Duplicate entry */
+ }
flag=0;
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
@@ -357,7 +367,7 @@ my_bool my_hash_insert(HASH *info,const byte *record)
{
/* Change link of previous LOW-key */
gpos->data=ptr_to_rec;
- gpos->next=(uint) (pos-data);
+ gpos->next= (uint) (pos-data);
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
}
gpos=pos;
@@ -406,7 +416,7 @@ my_bool my_hash_insert(HASH *info,const byte *record)
pos=data+idx;
if (pos == empty)
{
- pos->data=(byte*) record;
+ pos->data=(uchar*) record;
pos->next=NO_RECORD;
}
else
@@ -416,12 +426,12 @@ my_bool my_hash_insert(HASH *info,const byte *record)
gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
if (pos == gpos)
{
- pos->data=(byte*) record;
+ pos->data=(uchar*) record;
pos->next=(uint) (empty - data);
}
else
{
- pos->data=(byte*) record;
+ pos->data=(uchar*) record;
pos->next=NO_RECORD;
movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
}
@@ -438,7 +448,7 @@ my_bool my_hash_insert(HASH *info,const byte *record)
** if there is a free-function it's called for record if found
******************************************************************************/
-my_bool hash_delete(HASH *hash,byte *record)
+my_bool hash_delete(HASH *hash,uchar *record)
{
uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
@@ -516,7 +526,7 @@ my_bool hash_delete(HASH *hash,byte *record)
exit:
VOID(pop_dynamic(&hash->array));
if (hash->free)
- (*hash->free)((byte*) record);
+ (*hash->free)((uchar*) record);
DBUG_RETURN(0);
}
@@ -525,11 +535,28 @@ exit:
This is much more efficent than using a delete & insert.
*/
-my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
+my_bool hash_update(HASH *hash, uchar *record, uchar *old_key,
+ size_t old_key_length)
{
- uint idx,new_index,new_pos_index,blength,records,empty;
+ uint new_index,new_pos_index,blength,records,empty;
+ size_t idx;
HASH_LINK org_link,*data,*previous,*pos;
DBUG_ENTER("hash_update");
+
+ if (HASH_UNIQUE & hash->flags)
+ {
+ HASH_SEARCH_STATE state;
+ uchar *found, *new_key= (uchar*) hash_key(hash, record, &idx, 1);
+ if ((found= hash_first(hash, new_key, idx, &state)))
+ {
+ do
+ {
+ if (found != record)
+ DBUG_RETURN(1); /* Duplicate entry */
+ }
+ while ((found= hash_next(hash, new_key, idx, &state)));
+ }
+ }
data=dynamic_element(&hash->array,0,HASH_LINK*);
blength=hash->blength; records=hash->records;
@@ -608,7 +635,7 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
}
-byte *hash_element(HASH *hash,uint idx)
+uchar *hash_element(HASH *hash,ulong idx)
{
if (idx < hash->records)
return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
@@ -621,7 +648,7 @@ byte *hash_element(HASH *hash,uint idx)
isn't changed
*/
-void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, byte *new_row)
+void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, uchar *new_row)
{
if (*current_record != NO_RECORD) /* Safety */
dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
diff --git a/mysys/list.c b/mysys/list.c
index ccc3f495093..aaadd686365 100644
--- a/mysys/list.c
+++ b/mysys/list.c
@@ -61,8 +61,8 @@ void list_free(LIST *root, uint free_data)
{
next=root->next;
if (free_data)
- my_free((gptr) root->data,MYF(0));
- my_free((gptr) root,MYF(0));
+ my_free((uchar*) root->data,MYF(0));
+ my_free((uchar*) root,MYF(0));
root=next;
}
}
@@ -101,7 +101,7 @@ uint list_length(LIST *list)
}
-int list_walk(LIST *list, list_walk_action action, gptr argument)
+int list_walk(LIST *list, list_walk_action action, uchar* argument)
{
int error=0;
while (list)
diff --git a/mysys/make-ccc b/mysys/make-ccc
index 9c54185682a..b34bd80e1d1 100755
--- a/mysys/make-ccc
+++ b/mysys/make-ccc
@@ -1,4 +1,4 @@
rm -f .deps/* raid.o mf_iocache.o libmysys.a
-ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c
+ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c
make raid.o mf_iocache.o my_lock.o
ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o
diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c
index a3abb3bc974..f0df0f3fa77 100644
--- a/mysys/mf_cache.c
+++ b/mysys/mf_cache.c
@@ -58,7 +58,7 @@ static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)),
*/
my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
- uint cache_size, myf cache_myflags)
+ size_t cache_size, myf cache_myflags)
{
DBUG_ENTER("open_cached_file");
cache->dir= dir ? my_strdup(dir,MYF(cache_myflags & MY_WME)) : (char*) 0;
diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c
index d1672e55b65..1b428ded751 100644
--- a/mysys/mf_dirname.c
+++ b/mysys/mf_dirname.c
@@ -18,9 +18,9 @@
/* Functions definied in this file */
-uint dirname_length(const char *name)
+size_t dirname_length(const char *name)
{
- register my_string pos,gpos;
+ register char *pos, *gpos;
#ifdef BASKSLASH_MBTAIL
CHARSET_INFO *fs= fs_character_set();
#endif
@@ -47,21 +47,31 @@ uint dirname_length(const char *name)
)
gpos=pos;
}
- return ((uint) (uint) (gpos+1-(char*) name));
+ return (size_t) (gpos+1-(char*) name);
}
- /* Gives directory part of filename. Directory ends with '/' */
- /* Returns length of directory part */
+/*
+ Gives directory part of filename. Directory ends with '/'
+
+ SYNOPSIS
+ dirname_part()
+ to Store directory name here
+ name Original name
+ to_length Store length of 'to' here
+
+ RETURN
+ # Length of directory part in 'name'
+*/
-uint dirname_part(my_string to, const char *name)
+size_t dirname_part(char *to, const char *name, size_t *to_res_length)
{
- uint length;
+ size_t length;
DBUG_ENTER("dirname_part");
DBUG_PRINT("enter",("'%s'",name));
length=dirname_length(name);
- convert_dirname(to, name, name+length);
+ *to_res_length= (size_t) (convert_dirname(to, name, name+length) - to);
DBUG_RETURN(length);
} /* dirname */
@@ -74,7 +84,7 @@ uint dirname_part(my_string to, const char *name)
to Store result here. Must be at least of size
min(FN_REFLEN, strlen(from) + 1) to make room
for adding FN_LIBCHAR at the end.
- from Original filename
+ from Original filename. May be == to
from_end Pointer at end of filename (normally end \0)
IMPLEMENTATION
@@ -102,6 +112,7 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
#ifdef BACKSLASH_MBTAIL
CHARSET_INFO *fs= fs_character_set();
#endif
+ DBUG_ENTER("convert_dirname");
/* We use -2 here, becasue we need place for the last FN_LIBCHAR */
if (!from_end || (from_end - from) > FN_REFLEN-2)
@@ -141,7 +152,7 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
}
#else
/* This is ok even if to == from, becasue we need to cut the string */
- to= strmake(to, from, (uint) (from_end-from));
+ to= strmake(to, from, (size_t) (from_end-from));
#endif
/* Add FN_LIBCHAR to the end of directory path */
@@ -150,5 +161,5 @@ char *convert_dirname(char *to, const char *from, const char *from_end)
*to++=FN_LIBCHAR;
*to=0;
}
- return to; /* Pointer to end of dir */
+ DBUG_RETURN(to); /* Pointer to end of dir */
} /* convert_dirname */
diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c
index 20e835fe641..da7fac3de73 100644
--- a/mysys/mf_fn_ext.c
+++ b/mysys/mf_fn_ext.c
@@ -33,21 +33,22 @@
points at the end ASCII(0) of the filename.
*/
-my_string fn_ext(const char *name)
+char *fn_ext(const char *name)
{
- register my_string pos,gpos;
+ register const char *pos, *gpos;
DBUG_ENTER("fn_ext");
DBUG_PRINT("mfunkt",("name: '%s'",name));
#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR) || defined(BASKSLASH_MBTAIL)
{
char buff[FN_REFLEN];
- gpos=(my_string) name+dirname_part(buff,(char*) name);
+ size_t res_length;
+ gpos= name+ dirname_part(buff,(char*) name, &res_length);
}
#else
if (!(gpos= strrchr(name, FN_LIBCHAR)))
- gpos= (my_string) name;
+ gpos= name;
#endif
pos=strchr(gpos,FN_EXTCHAR);
- DBUG_RETURN (pos ? pos : strend(gpos));
+ DBUG_RETURN((char*) (pos ? pos : strend(gpos)));
} /* fn_ext */
diff --git a/mysys/mf_format.c b/mysys/mf_format.c
index 7a861c9f1e6..f199132626b 100644
--- a/mysys/mf_format.c
+++ b/mysys/mf_format.c
@@ -23,18 +23,19 @@
The arguments should be in unix format.
*/
-my_string fn_format(my_string to, const char *name, const char *dir,
+char * fn_format(char * to, const char *name, const char *dir,
const char *extension, uint flag)
{
- reg1 uint length;
char dev[FN_REFLEN], buff[FN_REFLEN], *pos, *startpos;
const char *ext;
+ reg1 size_t length;
+ size_t dev_length;
DBUG_ENTER("fn_format");
DBUG_PRINT("enter",("name: %s dir: %s extension: %s flag: %d",
name,dir,extension,flag));
/* Copy and skip directory */
- name+=(length=dirname_part(dev,(startpos=(my_string) name)));
+ name+=(length=dirname_part(dev, (startpos=(char *) name), &dev_length));
if (length == 0 || (flag & MY_REPLACE_DIR))
{
/* Use given directory */
@@ -53,7 +54,8 @@ my_string fn_format(my_string to, const char *name, const char *dir,
if (flag & MY_UNPACK_FILENAME)
(void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
- if ((pos= (char*) strchr(name,FN_EXTCHAR)) != NullS)
+ if (!(flag & MY_APPEND_EXT) &&
+ (pos= (char*) strchr(name,FN_EXTCHAR)) != NullS)
{
if ((flag & MY_REPLACE_EXT) == 0) /* If we should keep old ext */
{
@@ -62,7 +64,7 @@ my_string fn_format(my_string to, const char *name, const char *dir,
}
else
{
- length=(uint) (pos-(char*) name); /* Change extension */
+ length= (size_t) (pos-(char*) name); /* Change extension */
ext= extension;
}
}
@@ -75,18 +77,19 @@ my_string fn_format(my_string to, const char *name, const char *dir,
if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
{
/* To long path, return original or NULL */
- uint tmp_length;
+ size_t tmp_length;
if (flag & MY_SAFE_PATH)
return NullS;
- tmp_length=strlength(startpos);
- DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %d",dev,ext,length));
+ tmp_length= strlength(startpos);
+ DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %u",dev,ext,
+ (uint) length));
(void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
}
else
{
if (to == startpos)
{
- bmove(buff,(char*) name,length); /* Save name for last copy */
+ bmove(buff,(uchar*) name,length); /* Save name for last copy */
name=buff;
}
pos=strmake(strmov(to,dev),name,length);
@@ -108,18 +111,18 @@ my_string fn_format(my_string to, const char *name, const char *dir,
} /* fn_format */
- /*
- strlength(const string str)
- Return length of string with end-space:s not counted.
- */
+/*
+ strlength(const string str)
+ Return length of string with end-space:s not counted.
+*/
-size_s strlength(const char *str)
+size_t strlength(const char *str)
{
- reg1 my_string pos;
- reg2 my_string found;
+ reg1 const char * pos;
+ reg2 const char * found;
DBUG_ENTER("strlength");
- pos=found=(char*) str;
+ pos= found= str;
while (*pos)
{
@@ -135,5 +138,5 @@ size_s strlength(const char *str)
found=pos;
while (*++pos == ' ') {};
}
- DBUG_RETURN((size_s) (found-(char*) str));
+ DBUG_RETURN((size_t) (found - str));
} /* strlength */
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index 1ced312848e..3a8e1be6a0b 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -34,7 +34,7 @@
*/
-void get_date(register my_string to, int flag, time_t date)
+void get_date(register char * to, int flag, time_t date)
{
reg2 struct tm *start_time;
time_t skr;
@@ -42,7 +42,7 @@ void get_date(register my_string to, int flag, time_t date)
struct tm tm_tmp;
#endif
- skr=date ? (time_t) date : time((time_t*) 0);
+ skr=date ? (time_t) date : my_time(0);
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
if (flag & GETDATE_GMT)
localtime_r(&skr,&tm_tmp);
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index d2ace12da4d..58650733490 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -152,11 +152,11 @@ init_functions(IO_CACHE* info)
# error
*/
-int init_io_cache(IO_CACHE *info, File file, uint cachesize,
+int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
enum cache_type type, my_off_t seek_offset,
pbool use_async_io, myf cache_myflags)
{
- uint min_cache;
+ size_t min_cache;
my_off_t pos;
my_off_t end_of_file= ~(my_off_t) 0;
DBUG_ENTER("init_io_cache");
@@ -214,7 +214,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
/* Trim cache size if the file is very small */
if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
{
- cachesize=(uint) (end_of_file-seek_offset)+IO_SIZE*2-1;
+ cachesize= (size_t) (end_of_file-seek_offset)+IO_SIZE*2-1;
use_async_io=0; /* No need to use async */
}
}
@@ -223,18 +223,17 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
if (type != READ_NET && type != WRITE_NET)
{
/* Retry allocating memory in smaller blocks until we get one */
- cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
- (ulong) ~(min_cache-1));
+ cachesize= ((cachesize + min_cache-1) & ~(min_cache-1));
for (;;)
{
- uint buffer_block;
+ size_t buffer_block;
if (cachesize < min_cache)
cachesize = min_cache;
- buffer_block = cachesize;
+ buffer_block= cachesize;
if (type == SEQ_READ_APPEND)
buffer_block *= 2;
if ((info->buffer=
- (byte*) my_malloc(buffer_block,
+ (uchar*) my_malloc(buffer_block,
MYF((cache_myflags & ~ MY_WME) |
(cachesize == min_cache ? MY_WME : 0)))) != 0)
{
@@ -247,11 +246,11 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
if (cachesize == min_cache)
DBUG_RETURN(2); /* Can't alloc cache */
/* Try with less memory */
- cachesize= (uint) ((ulong) cachesize*3/4 & (ulong)~(min_cache-1));
+ cachesize= (cachesize*3/4 & ~(min_cache-1));
}
}
- DBUG_PRINT("info",("init_io_cache: cachesize = %u",cachesize));
+ DBUG_PRINT("info",("init_io_cache: cachesize = %lu", (ulong) cachesize));
info->read_length=info->buffer_length=cachesize;
info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
info->request_pos= info->read_pos= info->write_pos = info->buffer;
@@ -350,7 +349,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
seek_offset <= my_b_tell(info))
{
/* Reuse current buffer without flushing it to disk */
- byte *pos;
+ uchar *pos;
if (info->type == WRITE_CACHE && type == READ_CACHE)
{
info->read_end=info->write_pos;
@@ -452,22 +451,22 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
1 Error: can't read requested characters
*/
-int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
+int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
{
- uint length,diff_length,left_length;
- my_off_t max_length, pos_in_file;
+ size_t length,diff_length,left_length, max_length;
+ my_off_t pos_in_file;
DBUG_ENTER("_my_b_read");
- if ((left_length=(uint) (info->read_end-info->read_pos)))
+ if ((left_length= (size_t) (info->read_end-info->read_pos)))
{
DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
- memcpy(Buffer,info->read_pos, (size_t) (left_length));
+ memcpy(Buffer,info->read_pos, left_length);
Buffer+=left_length;
Count-=left_length;
}
/* pos_in_file always point on where info->buffer was read */
- pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer);
+ pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
/*
Whenever a function which operates on IO_CACHE flushes/writes
@@ -496,20 +495,20 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
}
- diff_length=(uint) (pos_in_file & (IO_SIZE-1));
- if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
+ diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
+ if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
{ /* Fill first intern buffer */
- uint read_length;
+ size_t read_length;
if (info->end_of_file <= pos_in_file)
{ /* End of file */
- info->error=(int) left_length;
+ info->error= (int) left_length;
DBUG_RETURN(1);
}
- length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
- if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags))
- != (uint) length)
+ length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
+ if ((read_length= my_read(info->file,Buffer, length, info->myflags))
+ != length)
{
- info->error= (read_length == (uint) -1 ? -1 :
+ info->error= (read_length == (size_t) -1 ? -1 :
(int) (read_length+left_length));
DBUG_RETURN(1);
}
@@ -520,10 +519,10 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
diff_length=0;
}
- max_length=info->read_length-diff_length;
+ max_length= info->read_length-diff_length;
if (info->type != READ_FIFO &&
max_length > (info->end_of_file - pos_in_file))
- max_length = info->end_of_file - pos_in_file;
+ max_length= (size_t) (info->end_of_file - pos_in_file);
if (!max_length)
{
if (Count)
@@ -533,21 +532,21 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
length=0; /* Didn't read any chars */
}
- else if ((length=my_read(info->file,info->buffer,(uint) max_length,
- info->myflags)) < Count ||
- length == (uint) -1)
+ else if ((length= my_read(info->file,info->buffer, max_length,
+ info->myflags)) < Count ||
+ length == (size_t) -1)
{
- if (length != (uint) -1)
- memcpy(Buffer,info->buffer,(size_t) length);
+ if (length != (size_t) -1)
+ memcpy(Buffer, info->buffer, length);
info->pos_in_file= pos_in_file;
- info->error= length == (uint) -1 ? -1 : (int) (length+left_length);
+ info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
info->read_pos=info->read_end=info->buffer;
DBUG_RETURN(1);
}
info->read_pos=info->buffer+Count;
info->read_end=info->buffer+length;
info->pos_in_file=pos_in_file;
- memcpy(Buffer,info->buffer,(size_t) Count);
+ memcpy(Buffer, info->buffer, Count);
DBUG_RETURN(0);
}
@@ -859,8 +858,9 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
/* Another thread did read the block already. */
}
DBUG_PRINT("io_cache_share", ("reader awoke, going to process %u bytes",
- cshare->read_end ? (uint)
- (cshare->read_end - cshare->buffer) : 0));
+ (uint) (cshare->read_end ? (size_t)
+ (cshare->read_end - cshare->buffer) :
+ 0)));
/*
Leave the lock. Do not call unlock_io_cache() later. The thread that
@@ -952,33 +952,33 @@ static void unlock_io_cache(IO_CACHE *cache)
1 Error: can't read requested characters
*/
-int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count)
+int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
{
my_off_t pos_in_file;
- uint length, diff_length, left_length;
+ size_t length, diff_length, left_length;
IO_CACHE_SHARE *cshare= cache->share;
DBUG_ENTER("_my_b_read_r");
- if ((left_length= (uint) (cache->read_end - cache->read_pos)))
+ if ((left_length= (size_t) (cache->read_end - cache->read_pos)))
{
DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
- memcpy(Buffer, cache->read_pos, (size_t) (left_length));
+ memcpy(Buffer, cache->read_pos, left_length);
Buffer+= left_length;
Count-= left_length;
}
while (Count)
{
- int cnt, len;
+ size_t cnt, len;
pos_in_file= cache->pos_in_file + (cache->read_end - cache->buffer);
- diff_length= (uint) (pos_in_file & (IO_SIZE-1));
+ diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
length=IO_ROUND_UP(Count+diff_length)-diff_length;
length= ((length <= cache->read_length) ?
length + IO_ROUND_DN(cache->read_length - length) :
length - IO_ROUND_UP(length - cache->read_length));
if (cache->type != READ_FIFO &&
(length > (cache->end_of_file - pos_in_file)))
- length= (uint) (cache->end_of_file - pos_in_file);
+ length= (size_t) (cache->end_of_file - pos_in_file);
if (length == 0)
{
cache->error= (int) left_length;
@@ -1013,12 +1013,12 @@ int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count)
DBUG_RETURN(1);
}
}
- len= (int) my_read(cache->file, cache->buffer, length, cache->myflags);
+ len= my_read(cache->file, cache->buffer, length, cache->myflags);
}
- DBUG_PRINT("io_cache_share", ("read %d bytes", len));
+ DBUG_PRINT("io_cache_share", ("read %lu bytes", (ulong) len));
- cache->read_end= cache->buffer + (len == -1 ? 0 : len);
- cache->error= (len == (int)length ? 0 : len);
+ cache->read_end= cache->buffer + (len == (size_t) -1 ? 0 : len);
+ cache->error= (len == length ? 0 : (int) len);
cache->pos_in_file= pos_in_file;
/* Copy important values to the share. */
@@ -1039,19 +1039,20 @@ int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count)
cache->read_end= cshare->read_end;
cache->pos_in_file= cshare->pos_in_file;
- len= (int) ((cache->error == -1) ? -1 : cache->read_end - cache->buffer);
+ len= ((cache->error == -1) ? (size_t) -1 :
+ (size_t) (cache->read_end - cache->buffer));
}
cache->read_pos= cache->buffer;
cache->seek_not_done= 0;
- if (len <= 0)
+ if (len == 0 || len == (size_t) -1)
{
- DBUG_PRINT("io_cache_share", ("reader error. len %d left %u",
- len, left_length));
+ DBUG_PRINT("io_cache_share", ("reader error. len %lu left %lu",
+ (ulong) len, (ulong) left_length));
cache->error= (int) left_length;
DBUG_RETURN(1);
}
- cnt= ((uint) len > Count) ? (int) Count : len;
- memcpy(Buffer, cache->read_pos, (size_t) cnt);
+ cnt= (len > Count) ? Count : len;
+ memcpy(Buffer, cache->read_pos, cnt);
Count -= cnt;
Buffer+= cnt;
left_length+= cnt;
@@ -1079,7 +1080,7 @@ int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count)
*/
static void copy_to_read_buffer(IO_CACHE *write_cache,
- const byte *write_buffer, uint write_length)
+ const uchar *write_buffer, size_t write_length)
{
IO_CACHE_SHARE *cshare= write_cache->share;
@@ -1090,7 +1091,7 @@ static void copy_to_read_buffer(IO_CACHE *write_cache,
*/
while (write_length)
{
- uint copy_length= min(write_length, write_cache->buffer_length);
+ size_t copy_length= min(write_length, write_cache->buffer_length);
int __attribute__((unused)) rc;
rc= lock_io_cache(write_cache, write_cache->pos_in_file);
@@ -1126,33 +1127,32 @@ static void copy_to_read_buffer(IO_CACHE *write_cache,
1 Failed to read
*/
-int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
+int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
{
- uint length,diff_length,left_length,save_count;
- my_off_t max_length, pos_in_file;
+ size_t length, diff_length, left_length, save_count, max_length;
+ my_off_t pos_in_file;
save_count=Count;
/* first, read the regular buffer */
- if ((left_length=(uint) (info->read_end-info->read_pos)))
+ if ((left_length=(size_t) (info->read_end-info->read_pos)))
{
DBUG_ASSERT(Count > left_length); /* User is not using my_b_read() */
- memcpy(Buffer,info->read_pos, (size_t) (left_length));
+ memcpy(Buffer,info->read_pos, left_length);
Buffer+=left_length;
Count-=left_length;
}
lock_append_buffer(info);
/* pos_in_file always point on where info->buffer was read */
- if ((pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer)) >=
- info->end_of_file)
+ if ((pos_in_file=info->pos_in_file +
+ (size_t) (info->read_end - info->buffer)) >= info->end_of_file)
goto read_append_buffer;
/*
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 (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) == MY_FILEPOS_ERROR)
{
info->error= -1;
unlock_append_buffer(info);
@@ -1160,16 +1160,17 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
info->seek_not_done=0;
- diff_length=(uint) (pos_in_file & (IO_SIZE-1));
+ diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
/* now the second stage begins - read from file descriptor */
- if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
- { /* Fill first intern buffer */
- uint read_length;
+ if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
+ {
+ /* Fill first intern buffer */
+ size_t read_length;
- length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
- if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags)) ==
- (uint)-1)
+ length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
+ if ((read_length= my_read(info->file,Buffer, length,
+ info->myflags)) == (size_t) -1)
{
info->error= -1;
unlock_append_buffer(info);
@@ -1179,7 +1180,7 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
Buffer+=read_length;
pos_in_file+=read_length;
- if (read_length != (uint) length)
+ if (read_length != length)
{
/*
We only got part of data; Read the rest of the data from the
@@ -1191,9 +1192,9 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
diff_length=0;
}
- max_length=info->read_length-diff_length;
+ max_length= info->read_length-diff_length;
if (max_length > (info->end_of_file - pos_in_file))
- max_length = info->end_of_file - pos_in_file;
+ max_length= (size_t) (info->end_of_file - pos_in_file);
if (!max_length)
{
if (Count)
@@ -1202,9 +1203,8 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
else
{
- length=my_read(info->file,info->buffer,(uint) max_length,
- info->myflags);
- if (length == (uint) -1)
+ length= my_read(info->file,info->buffer, max_length, info->myflags);
+ if (length == (size_t) -1)
{
info->error= -1;
unlock_append_buffer(info);
@@ -1212,7 +1212,7 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
if (length < Count)
{
- memcpy(Buffer,info->buffer,(size_t) length);
+ memcpy(Buffer, info->buffer, length);
Count -= length;
Buffer += length;
@@ -1241,9 +1241,9 @@ read_append_buffer:
{
/* First copy the data to Count */
- uint len_in_buff = (uint) (info->write_pos - info->append_read_pos);
- uint copy_len;
- uint transfer_len;
+ size_t len_in_buff = (size_t) (info->write_pos - info->append_read_pos);
+ size_t copy_len;
+ size_t transfer_len;
DBUG_ASSERT(info->append_read_pos <= info->write_pos);
/*
@@ -1288,15 +1288,16 @@ read_append_buffer:
0 Success
1 An error has occurred; IO_CACHE to error state.
*/
-int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
+
+int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
{
- uint length,read_length,diff_length,left_length,use_length,org_Count;
- my_off_t max_length;
+ size_t length,read_length,diff_length,left_length,use_length,org_Count;
+ size_t max_length;
my_off_t next_pos_in_file;
- byte *read_buffer;
+ uchar *read_buffer;
memcpy(Buffer,info->read_pos,
- (size_t) (left_length=(uint) (info->read_end-info->read_pos)));
+ (left_length= (size_t) (info->read_end-info->read_pos)));
Buffer+=left_length;
org_Count=Count;
Count-=left_length;
@@ -1315,15 +1316,15 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
info->error= -1;
return(1);
}
- if (! (read_length = (uint) info->aio_result.result.aio_return) ||
- read_length == (uint) -1)
+ if (! (read_length= (size_t) info->aio_result.result.aio_return) ||
+ read_length == (size_t) -1)
{
my_errno=0; /* For testing */
- info->error= (read_length == (uint) -1 ? -1 :
+ info->error= (read_length == (size_t) -1 ? -1 :
(int) (read_length+left_length));
return(1);
}
- info->pos_in_file+=(uint) (info->read_end - info->request_pos);
+ info->pos_in_file+= (size_t) (info->read_end - info->request_pos);
if (info->request_pos != info->buffer)
info->request_pos=info->buffer;
@@ -1354,7 +1355,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (info->aio_read_pos > info->pos_in_file)
{
my_errno=EINVAL;
- return(info->read_length= -1);
+ return(info->read_length= (size_t) -1);
}
#endif
/* Copy found bytes to buffer */
@@ -1367,7 +1368,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
info->read_pos+=length;
}
else
- next_pos_in_file=(info->pos_in_file+ (uint)
+ next_pos_in_file=(info->pos_in_file+ (size_t)
(info->read_end - info->request_pos));
/* If reading large blocks, or first read or read with skip */
@@ -1386,11 +1387,11 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
return (1);
}
- read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1));
+ 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)) == (uint) -1)
+ 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);
@@ -1410,10 +1411,10 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
else
{ /* Big block, don't cache it */
- if ((read_length=my_read(info->file,Buffer,(uint) Count,info->myflags))
+ if ((read_length= my_read(info->file,Buffer, Count,info->myflags))
!= Count)
{
- info->error= read_length == (uint) -1 ? -1 : read_length+left_length;
+ info->error= read_length == (size_t) -1 ? -1 : read_length+left_length;
return 1;
}
info->read_pos=info->read_end=info->request_pos;
@@ -1421,12 +1422,12 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
}
}
- /* Read next block with asyncronic io */
- max_length=info->end_of_file - next_pos_in_file;
+ /* Read next block with asyncronic io */
diff_length=(next_pos_in_file & (IO_SIZE-1));
+ max_length= info->read_length - diff_length;
+ if (max_length > info->end_of_file - next_pos_in_file)
+ max_length= (size_t) (info->end_of_file - next_pos_in_file);
- if (max_length > (my_off_t) info->read_length - diff_length)
- max_length= (my_off_t) info->read_length - diff_length;
if (info->request_pos != info->buffer)
read_buffer=info->buffer;
else
@@ -1435,9 +1436,9 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (max_length)
{
info->aio_result.result.aio_errno=AIO_INPROGRESS; /* Marker for test */
- DBUG_PRINT("aioread",("filepos: %ld length: %ld",
- (ulong) next_pos_in_file,(ulong) max_length));
- if (aioread(info->file,read_buffer,(int) max_length,
+ DBUG_PRINT("aioread",("filepos: %ld length: %lu",
+ (ulong) next_pos_in_file, (ulong) max_length));
+ if (aioread(info->file,read_buffer, max_length,
(my_off_t) next_pos_in_file,MY_SEEK_SET,
&info->aio_result.result))
{ /* Skip async io */
@@ -1447,7 +1448,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
if (info->request_pos != info->buffer)
{
bmove(info->buffer,info->request_pos,
- (uint) (info->read_end - info->read_pos));
+ (size_t) (info->read_end - info->read_pos));
info->request_pos=info->buffer;
info->read_pos-=info->read_length;
info->read_end-=info->read_length;
@@ -1467,7 +1468,7 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
int _my_b_get(IO_CACHE *info)
{
- byte buff;
+ uchar buff;
IO_CACHE_CALLBACK pre_read,post_read;
if ((pre_read = info->pre_read))
(*pre_read)(info);
@@ -1488,9 +1489,9 @@ int _my_b_get(IO_CACHE *info)
-1 On error; my_errno contains error code.
*/
-int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
+int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
{
- uint rest_length,length;
+ size_t rest_length,length;
if (info->pos_in_file+info->buffer_length > info->end_of_file)
{
@@ -1498,7 +1499,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
return info->error = -1;
}
- rest_length=(uint) (info->write_end - info->write_pos);
+ rest_length= (size_t) (info->write_end - info->write_pos);
memcpy(info->write_pos,Buffer,(size_t) rest_length);
Buffer+=rest_length;
Count-=rest_length;
@@ -1508,7 +1509,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
return 1;
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
- length=Count & (uint) ~(IO_SIZE-1);
+ length=Count & (size_t) ~(IO_SIZE-1);
if (info->seek_not_done)
{
/*
@@ -1524,7 +1525,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
}
info->seek_not_done=0;
}
- if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
+ if (my_write(info->file, Buffer, length, info->myflags | MY_NABP))
return info->error= -1;
#ifdef THREAD
@@ -1559,9 +1560,9 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
the write buffer before we are ready with it.
*/
-int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
+int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
{
- uint rest_length,length;
+ size_t rest_length,length;
#ifdef THREAD
/*
@@ -1572,10 +1573,10 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
#endif
lock_append_buffer(info);
- rest_length=(uint) (info->write_end - info->write_pos);
+ rest_length= (size_t) (info->write_end - info->write_pos);
if (Count <= rest_length)
goto end;
- memcpy(info->write_pos,Buffer,(size_t) rest_length);
+ memcpy(info->write_pos, Buffer, rest_length);
Buffer+=rest_length;
Count-=rest_length;
info->write_pos+=rest_length;
@@ -1586,8 +1587,8 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
}
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
- length=Count & (uint) ~(IO_SIZE-1);
- if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
+ length=Count & (size_t) ~(IO_SIZE-1);
+ if (my_write(info->file,Buffer, length, info->myflags | MY_NABP))
{
unlock_append_buffer(info);
return info->error= -1;
@@ -1605,7 +1606,7 @@ end:
}
-int my_b_safe_write(IO_CACHE *info, const byte *Buffer, uint Count)
+int my_b_safe_write(IO_CACHE *info, const uchar *Buffer, size_t Count)
{
/*
Sasha: We are not writing this with the ? operator to avoid hitting
@@ -1625,10 +1626,10 @@ int my_b_safe_write(IO_CACHE *info, const byte *Buffer, uint Count)
we will never get a seek over the end of the buffer
*/
-int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
+int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
my_off_t pos)
{
- uint length;
+ size_t length;
int error=0;
#ifdef THREAD
@@ -1648,7 +1649,7 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
/* 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))
- info->error=error=-1;
+ info->error= error= -1;
Buffer+=length;
pos+= length;
Count-= length;
@@ -1658,10 +1659,10 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
}
/* Check if we want to write inside the used part of the buffer.*/
- length= (uint) (info->write_end - info->buffer);
+ length= (size_t) (info->write_end - info->buffer);
if (pos < info->pos_in_file + length)
{
- uint offset= (uint) (pos - info->pos_in_file);
+ size_t offset= (size_t) (pos - info->pos_in_file);
length-=offset;
if (length > Count)
length=Count;
@@ -1696,7 +1697,7 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
{
- uint length;
+ size_t length;
my_bool append_cache;
my_off_t pos_in_file;
DBUG_ENTER("my_b_flush_io_cache");
@@ -1713,7 +1714,7 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
}
LOCK_APPEND_BUFFER;
- if ((length=(uint) (info->write_pos - info->write_buffer)))
+ if ((length=(size_t) (info->write_pos - info->write_buffer)))
{
#ifdef THREAD
/*
@@ -1821,8 +1822,8 @@ 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((gptr) info->buffer,MYF(MY_WME));
- info->buffer=info->read_pos=(byte*) 0;
+ my_free((uchar*) info->buffer,MYF(MY_WME));
+ info->buffer=info->read_pos=(uchar*) 0;
}
if (info->type == SEQ_READ_APPEND)
{
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index 30e9f19a189..c54c7d13548 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -23,6 +23,51 @@
#include <stdarg.h>
#include <m_ctype.h>
+/*
+ Copy contents of an IO_CACHE to a file.
+
+ SYNOPSIS
+ my_b_copy_to_file()
+ cache IO_CACHE to copy from
+ file File to copy to
+
+ DESCRIPTION
+ Copy the contents of the cache to the file. The cache will be
+ re-inited to a read cache and will read from the beginning of the
+ cache.
+
+ If a failure to write fully occurs, the cache is only copied
+ partially.
+
+ TODO
+ Make this function solid by handling partial reads from the cache
+ in a correct manner: it should be atomic.
+
+ RETURN VALUE
+ 0 All OK
+ 1 An error occured
+*/
+int
+my_b_copy_to_file(IO_CACHE *cache, FILE *file)
+{
+ size_t bytes_in_cache;
+ DBUG_ENTER("my_b_copy_to_file");
+
+ /* Reinit the cache to read from the beginning of the cache */
+ if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
+ DBUG_RETURN(1);
+ bytes_in_cache= my_b_bytes_in_cache(cache);
+ do
+ {
+ if (my_fwrite(file, cache->read_pos, bytes_in_cache,
+ MYF(MY_WME | MY_NABP)) == (size_t) -1)
+ DBUG_RETURN(1);
+ cache->read_pos= cache->read_end;
+ } while ((bytes_in_cache= my_b_fill(cache)));
+ DBUG_RETURN(0);
+}
+
+
my_off_t my_b_append_tell(IO_CACHE* info)
{
/*
@@ -130,18 +175,24 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
/*
- Fill buffer. Note that this assumes that you have already used
- all characters in the CACHE, independent of the read_pos value!
- return: 0 on error or EOF (info->error = -1 on error)
- number of characters
+ Fill buffer of the cache.
+
+ NOTES
+ This assumes that you have already used all characters in the CACHE,
+ independent of the read_pos value!
+
+ RETURN
+ 0 On error or EOF (info->error = -1 on error)
+ # Number of characters
*/
-uint my_b_fill(IO_CACHE *info)
+
+size_t my_b_fill(IO_CACHE *info)
{
my_off_t pos_in_file=(info->pos_in_file+
- (uint) (info->read_end - info->buffer));
- my_off_t max_length;
- uint diff_length,length;
+ (size_t) (info->read_end - info->buffer));
+ size_t diff_length, length, max_length;
+
if (info->seek_not_done)
{ /* File touched, do seek */
if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) ==
@@ -152,17 +203,18 @@ uint my_b_fill(IO_CACHE *info)
}
info->seek_not_done=0;
}
- diff_length=(uint) (pos_in_file & (IO_SIZE-1));
- max_length= (my_off_t) (info->end_of_file - pos_in_file);
- if (max_length > (my_off_t) (info->read_length-diff_length))
- max_length=(my_off_t) (info->read_length-diff_length);
+ diff_length=(size_t) (pos_in_file & (IO_SIZE-1));
+ max_length=(info->read_length-diff_length);
+ if (max_length >= (info->end_of_file - pos_in_file))
+ max_length= (size_t) (info->end_of_file - pos_in_file);
+
if (!max_length)
{
info->error= 0;
return 0; /* EOF */
}
- else if ((length=my_read(info->file,info->buffer,(uint) max_length,
- info->myflags)) == (uint) -1)
+ if ((length= my_read(info->file,info->buffer,max_length,
+ info->myflags)) == (size_t) -1)
{
info->error= -1;
return 0;
@@ -181,18 +233,20 @@ uint my_b_fill(IO_CACHE *info)
If buffer is full then to[max_length-1] will be set to \0.
*/
-uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
+size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length)
{
char *start = to;
- uint length;
+ size_t length;
max_length--; /* Save place for end \0 */
+
/* Calculate number of characters in buffer */
if (!(length= my_b_bytes_in_cache(info)) &&
!(length= my_b_fill(info)))
return 0;
+
for (;;)
{
- char *pos,*end;
+ uchar *pos, *end;
if (length > max_length)
length=max_length;
for (pos=info->read_pos,end=pos+length ; pos < end ;)
@@ -201,7 +255,7 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
{
info->read_pos=pos;
*to='\0';
- return (uint) (to-start);
+ return (size_t) (to-start);
}
}
if (!(max_length-=length))
@@ -209,7 +263,7 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
/* Found enough charcters; Return found string */
info->read_pos=pos;
*to='\0';
- return (uint) (to-start);
+ return (size_t) (to-start);
}
if (!(length=my_b_fill(info)))
return 0;
@@ -220,26 +274,22 @@ uint my_b_gets(IO_CACHE *info, char *to, uint max_length)
my_off_t my_b_filelength(IO_CACHE *info)
{
if (info->type == WRITE_CACHE)
- {
return my_b_tell(info);
- }
- else
- {
- info->seek_not_done=1;
- return my_seek(info->file,0L,MY_SEEK_END,MYF(0));
- }
+
+ info->seek_not_done= 1;
+ return my_seek(info->file, 0L, MY_SEEK_END, MYF(0));
}
/*
Simple printf version. Supports '%s', '%d', '%u', "%ld" and "%lu"
Used for logging in MySQL
- returns number of written character, or (uint) -1 on error
+ returns number of written character, or (size_t) -1 on error
*/
-uint my_b_printf(IO_CACHE *info, const char* fmt, ...)
+size_t my_b_printf(IO_CACHE *info, const char* fmt, ...)
{
- int result;
+ size_t result;
va_list args;
va_start(args,fmt);
result=my_b_vprintf(info, fmt, args);
@@ -248,12 +298,13 @@ uint my_b_printf(IO_CACHE *info, const char* fmt, ...)
}
-uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
+size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
{
- uint out_length=0;
+ size_t out_length= 0;
uint minimum_width; /* as yet unimplemented */
uint minimum_width_sign;
uint precision; /* as yet unimplemented for anything but %b */
+ my_bool is_zero_padded;
/*
Store the location of the beginning of a format directive, for the
@@ -267,19 +318,17 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
{
/* Copy everything until '%' or end of string */
const char *start=fmt;
- uint length;
+ size_t length;
for (; (*fmt != '\0') && (*fmt != '%'); fmt++) ;
- length= (uint) (fmt - start);
+ length= (size_t) (fmt - start);
out_length+=length;
- if (my_b_write(info, start, length))
+ if (my_b_write(info, (const uchar*) start, length))
goto err;
if (*fmt == '\0') /* End of format */
- {
return out_length;
- }
/*
By this point, *fmt must be a percent; Keep track of this location and
@@ -289,15 +338,34 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
backtrack= fmt;
fmt++;
+ is_zero_padded= FALSE;
+ minimum_width_sign= 1;
minimum_width= 0;
precision= 0;
- minimum_width_sign= 1;
/* Skip if max size is used (to be compatible with printf) */
- while (*fmt == '-') { fmt++; minimum_width_sign= -1; }
- if (*fmt == '*') {
+
+process_flags:
+ switch (*fmt)
+ {
+ case '-':
+ minimum_width_sign= -1; fmt++; goto process_flags;
+ case '0':
+ is_zero_padded= TRUE; fmt++; goto process_flags;
+ case '#':
+ /** @todo Implement "#" conversion flag. */ fmt++; goto process_flags;
+ case ' ':
+ /** @todo Implement " " conversion flag. */ fmt++; goto process_flags;
+ case '+':
+ /** @todo Implement "+" conversion flag. */ fmt++; goto process_flags;
+ }
+
+ if (*fmt == '*')
+ {
precision= (int) va_arg(args, int);
fmt++;
- } else {
+ }
+ else
+ {
while (my_isdigit(&my_charset_latin1, *fmt)) {
minimum_width=(minimum_width * 10) + (*fmt - '0');
fmt++;
@@ -305,12 +373,15 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
}
minimum_width*= minimum_width_sign;
- if (*fmt == '.') {
+ if (*fmt == '.')
+ {
fmt++;
if (*fmt == '*') {
precision= (int) va_arg(args, int);
fmt++;
- } else {
+ }
+ else
+ {
while (my_isdigit(&my_charset_latin1, *fmt)) {
precision=(precision * 10) + (*fmt - '0');
fmt++;
@@ -321,54 +392,69 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
if (*fmt == 's') /* String parameter */
{
reg2 char *par = va_arg(args, char *);
- uint length2 = (uint) strlen(par);
- /* TODO: implement minimum width and precision */
+ size_t length2 = strlen(par);
+ /* TODO: implement precision */
out_length+= length2;
- if (my_b_write(info, par, length2))
+ if (my_b_write(info, (uchar*) par, length2))
goto err;
}
else if (*fmt == 'b') /* Sized buffer parameter, only precision makes sense */
{
char *par = va_arg(args, char *);
out_length+= precision;
- if (my_b_write(info, par, precision))
+ if (my_b_write(info, (uchar*) par, precision))
goto err;
}
else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
{
register int iarg;
- uint length2;
+ size_t length2;
char buff[17];
iarg = va_arg(args, int);
if (*fmt == 'd')
- length2= (uint) (int10_to_str((long) iarg,buff, -10) - buff);
+ length2= (size_t) (int10_to_str((long) iarg,buff, -10) - buff);
else
- length2= (uint) (int10_to_str((long) (uint) iarg,buff,10)- buff);
+ length2= (uint) (int10_to_str((long) (uint) iarg,buff,10)- buff);
+
+ /* minimum width padding */
+ if (minimum_width > length2)
+ {
+ char *buffz;
+
+ buffz= my_alloca(minimum_width - length2);
+ if (is_zero_padded)
+ memset(buffz, '0', minimum_width - length2);
+ else
+ memset(buffz, ' ', minimum_width - length2);
+ my_b_write(info, buffz, minimum_width - length2);
+ my_afree(buffz);
+ }
+
out_length+= length2;
- if (my_b_write(info, buff, length2))
+ if (my_b_write(info, (uchar*) buff, length2))
goto err;
}
else if ((*fmt == 'l' && fmt[1] == 'd') || fmt[1] == 'u')
/* long parameter */
{
register long iarg;
- uint length2;
+ size_t length2;
char buff[17];
iarg = va_arg(args, long);
if (*++fmt == 'd')
- length2= (uint) (int10_to_str(iarg,buff, -10) - buff);
+ length2= (size_t) (int10_to_str(iarg,buff, -10) - buff);
else
- length2= (uint) (int10_to_str(iarg,buff,10)- buff);
+ length2= (size_t) (int10_to_str(iarg,buff,10)- buff);
out_length+= length2;
- if (my_b_write(info, buff, length2))
+ if (my_b_write(info, (uchar*) buff, length2))
goto err;
}
else
{
/* %% or unknown code */
- if (my_b_write(info, backtrack, fmt-backtrack))
+ if (my_b_write(info, (uchar*) backtrack, (size_t) (fmt-backtrack)))
goto err;
out_length+= fmt-backtrack;
}
@@ -376,5 +462,5 @@ uint my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
return out_length;
err:
- return (uint) -1;
+ return (size_t) -1;
}
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index af910678a1f..c81da9a469a 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -36,6 +36,69 @@
blocks_unused is the sum of never used blocks in the pool and of currently
free blocks. blocks_used is the number of blocks fetched from the pool and
as such gives the maximum number of in-use blocks at any time.
+
+ Key Cache Locking
+ =================
+
+ All key cache locking is done with a single mutex per key cache:
+ keycache->cache_lock. This mutex is locked almost all the time
+ when executing code in this file (mf_keycache.c).
+ However it is released for I/O and some copy operations.
+
+ The cache_lock is also released when waiting for some event. Waiting
+ and signalling is done via condition variables. In most cases the
+ thread waits on its thread->suspend condition variable. Every thread
+ has a my_thread_var structure, which contains this variable and a
+ '*next' and '**prev' pointer. These pointers are used to insert the
+ thread into a wait queue.
+
+ A thread can wait for one block and thus be in one wait queue at a
+ time only.
+
+ Before starting to wait on its condition variable with
+ pthread_cond_wait(), the thread enters itself to a specific wait queue
+ with link_into_queue() (double linked with '*next' + '**prev') or
+ wait_on_queue() (single linked with '*next').
+
+ Another thread, when releasing a resource, looks up the waiting thread
+ in the related wait queue. It sends a signal with
+ pthread_cond_signal() to the waiting thread.
+
+ NOTE: Depending on the particular wait situation, either the sending
+ thread removes the waiting thread from the wait queue with
+ unlink_from_queue() or release_whole_queue() respectively, or the waiting
+ thread removes itself.
+
+ There is one exception from this locking scheme when one thread wants
+ to reuse a block for some other address. This works by first marking
+ the block reserved (status= BLOCK_IN_SWITCH) and then waiting for all
+ threads that are reading the block to finish. Each block has a
+ reference to a condition variable (condvar). It holds a reference to
+ the thread->suspend condition variable for the waiting thread (if such
+ a thread exists). When that thread is signaled, the reference is
+ cleared. The number of readers of a block is registered in
+ block->hash_link->requests. See wait_for_readers() / remove_reader()
+ for details. This is similar to the above, but it clearly means that
+ only one thread can wait for a particular block. There is no queue in
+ this case. Strangely enough block->convar is used for waiting for the
+ assigned hash_link only. More precisely it is used to wait for all
+ requests to be unregistered from the assigned hash_link.
+
+ The resize_queue serves two purposes:
+ 1. Threads that want to do a resize wait there if in_resize is set.
+ This is not used in the server. The server refuses a second resize
+ request if one is already active. keycache->in_init is used for the
+ synchronization. See set_var.cc.
+ 2. Threads that want to access blocks during resize wait here during
+ the re-initialization phase.
+ When the resize is done, all threads on the queue are signalled.
+ Hypothetical resizers can compete for resizing, and read/write
+ requests will restart to request blocks from the freshly resized
+ cache. If the cache has been resized too small, it is disabled and
+ 'can_be_used' is false. In this case read/write requests bypass the
+ cache. Since they increment and decrement 'cnt_for_resize_op', the
+ next resizer can wait on the queue 'waiting_for_resize_cnt' until all
+ I/O finished.
*/
#include "mysys_priv.h"
@@ -83,14 +146,6 @@
#define KEYCACHE_DEBUG_LOG "my_key_cache_debug.log"
*/
-#if defined(MSDOS) && !defined(M_IC80386)
-/* we nead much memory */
-#undef my_malloc_lock
-#undef my_free_lock
-#define my_malloc_lock(A,B) halloc((long) (A/IO_SIZE),IO_SIZE)
-#define my_free_lock(A,B) hfree(A)
-#endif /* defined(MSDOS) && !defined(M_IC80386) */
-
#define STRUCT_PTR(TYPE, MEMBER, a) \
(TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
@@ -119,12 +174,16 @@ struct st_hash_link
};
/* simple states of a block */
-#define BLOCK_ERROR 1 /* an error occured when performing disk i/o */
-#define BLOCK_READ 2 /* the is page in the block buffer */
-#define BLOCK_IN_SWITCH 4 /* block is preparing to read new page */
-#define BLOCK_REASSIGNED 8 /* block does not accept requests for old page */
-#define BLOCK_IN_FLUSH 16 /* block is in flush operation */
-#define BLOCK_CHANGED 32 /* block buffer contains a dirty page */
+#define BLOCK_ERROR 1 /* an error occured when performing file i/o */
+#define BLOCK_READ 2 /* file block is in the block buffer */
+#define BLOCK_IN_SWITCH 4 /* block is preparing to read new page */
+#define BLOCK_REASSIGNED 8 /* blk does not accept requests for old page */
+#define BLOCK_IN_FLUSH 16 /* block is selected for flush */
+#define BLOCK_CHANGED 32 /* block buffer contains a dirty page */
+#define BLOCK_IN_USE 64 /* block is not free */
+#define BLOCK_IN_EVICTION 128 /* block is selected for eviction */
+#define BLOCK_IN_FLUSHWRITE 256 /* block is in write to file */
+#define BLOCK_FOR_UPDATE 512 /* block is selected for buffer modification */
/* page status, returned by find_key_block */
#define PAGE_READ 0
@@ -144,7 +203,7 @@ struct st_block_link
struct st_hash_link *hash_link; /* backward ptr to referring hash_link */
KEYCACHE_WQUEUE wqueue[2]; /* queues on waiting requests for new/old pages */
uint requests; /* number of requests for the block */
- byte *buffer; /* buffer for the block page */
+ uchar *buffer; /* buffer for the block page */
uint offset; /* beginning of modified data in the buffer */
uint length; /* end of data in the buffer */
uint status; /* state of the block */
@@ -161,13 +220,15 @@ KEY_CACHE *dflt_key_cache= &dflt_key_cache_var;
static int flush_all_key_blocks(KEY_CACHE *keycache);
#ifdef THREAD
-static void link_into_queue(KEYCACHE_WQUEUE *wqueue,
- struct st_my_thread_var *thread);
-static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
- struct st_my_thread_var *thread);
+static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
+ pthread_mutex_t *mutex);
+static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
+#else
+#define wait_on_queue(wqueue, mutex) do {} while (0)
+#define release_whole_queue(wqueue) do {} while (0)
#endif
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
-#ifndef DBUG_OFF
+#if !defined(DBUG_OFF)
static void test_key_cache(KEY_CACHE *keycache,
const char *where, my_bool lock);
#endif
@@ -263,15 +324,19 @@ static int keycache_pthread_cond_signal(pthread_cond_t *cond);
#define keycache_pthread_cond_signal pthread_cond_signal
#endif /* defined(KEYCACHE_DEBUG) */
-static uint next_power(uint value)
+#if !defined(DBUG_OFF)
+#if defined(inline)
+#undef inline
+#endif
+#define inline /* disabled inline for easier debugging */
+static int fail_block(BLOCK_LINK *block);
+static int fail_hlink(HASH_LINK *hlink);
+static int cache_empty(KEY_CACHE *keycache);
+#endif
+
+static inline uint next_power(uint value)
{
- uint old_value= 1;
- while (value)
- {
- old_value= value;
- value&= value-1;
- }
- return (old_value << 1);
+ return (uint) my_round_up_to_next_power((uint32) value) << 1;
}
@@ -301,10 +366,11 @@ static uint next_power(uint value)
*/
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
- ulong use_mem, uint division_limit,
+ size_t use_mem, uint division_limit,
uint age_threshold)
{
- uint blocks, hash_links, length;
+ ulong blocks, hash_links;
+ size_t length;
int error;
DBUG_ENTER("init_key_cache");
DBUG_ASSERT(key_cache_block_size >= 512);
@@ -322,6 +388,14 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
if (! keycache->key_cache_inited)
{
keycache->key_cache_inited= 1;
+ /*
+ Initialize these variables once only.
+ Their value must survive re-initialization during resizing.
+ */
+ keycache->in_resize= 0;
+ keycache->resize_in_flush= 0;
+ keycache->cnt_for_resize_op= 0;
+ keycache->waiting_for_resize_cnt.last_thread= NULL;
keycache->in_init= 0;
pthread_mutex_init(&keycache->cache_lock, MY_MUTEX_INIT_FAST);
keycache->resize_queue.last_thread= NULL;
@@ -332,10 +406,10 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
DBUG_PRINT("info", ("key_cache_block_size: %u",
key_cache_block_size));
- blocks= (uint) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
- sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
+ blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
+ sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
/* It doesn't make sense to have too few blocks (less than 8) */
- if (blocks >= 8 && keycache->disk_blocks < 0)
+ if (blocks >= 8)
{
for ( ; ; )
{
@@ -351,18 +425,18 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
ALIGN_SIZE(hash_links * sizeof(HASH_LINK)) +
ALIGN_SIZE(sizeof(HASH_LINK*) *
keycache->hash_entries))) +
- ((ulong) blocks * keycache->key_cache_block_size) > use_mem)
+ ((size_t) blocks * keycache->key_cache_block_size) > use_mem)
blocks--;
/* Allocate memory for cache page buffers */
if ((keycache->block_mem=
- my_large_malloc((ulong) blocks * keycache->key_cache_block_size,
+ my_large_malloc((size_t) blocks * keycache->key_cache_block_size,
MYF(MY_WME))))
{
/*
Allocate memory for blocks, hash_links and hash entries;
For each block 2 hash links are allocated
*/
- if ((keycache->block_root= (BLOCK_LINK*) my_malloc((uint) length,
+ if ((keycache->block_root= (BLOCK_LINK*) my_malloc(length,
MYF(0))))
break;
my_large_free(keycache->block_mem, MYF(0));
@@ -375,7 +449,7 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
}
blocks= blocks / 4*3;
}
- keycache->blocks_unused= (ulong) blocks;
+ keycache->blocks_unused= blocks;
keycache->disk_blocks= (int) blocks;
keycache->hash_links= hash_links;
keycache->hash_root= (HASH_LINK**) ((char*) keycache->block_root +
@@ -383,11 +457,11 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
ALIGN_SIZE((sizeof(HASH_LINK*) *
keycache->hash_entries)));
- bzero((byte*) keycache->block_root,
+ bzero((uchar*) keycache->block_root,
keycache->disk_blocks * sizeof(BLOCK_LINK));
- bzero((byte*) keycache->hash_root,
+ bzero((uchar*) keycache->hash_root,
keycache->hash_entries * sizeof(HASH_LINK*));
- bzero((byte*) keycache->hash_link_root,
+ bzero((uchar*) keycache->hash_link_root,
keycache->hash_links * sizeof(HASH_LINK));
keycache->hash_links_used= 0;
keycache->free_hash_list= NULL;
@@ -409,8 +483,6 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
blocks * age_threshold / 100 :
blocks);
- keycache->cnt_for_resize_op= 0;
- keycache->resize_in_flush= 0;
keycache->can_be_used= 1;
keycache->waiting_for_hash_link.last_thread= NULL;
@@ -421,11 +493,16 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
keycache->disk_blocks, (long) keycache->block_root,
keycache->hash_entries, (long) keycache->hash_root,
keycache->hash_links, (long) keycache->hash_link_root));
- bzero((gptr) keycache->changed_blocks,
+ bzero((uchar*) keycache->changed_blocks,
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
- bzero((gptr) keycache->file_blocks,
+ bzero((uchar*) keycache->file_blocks,
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
}
+ else
+ {
+ /* key_buffer_size is specified too small. Disable the cache. */
+ keycache->can_be_used= 0;
+ }
keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
DBUG_RETURN((int) keycache->disk_blocks);
@@ -436,12 +513,12 @@ err:
keycache->blocks= 0;
if (keycache->block_mem)
{
- my_large_free((gptr) keycache->block_mem, MYF(0));
+ my_large_free((uchar*) keycache->block_mem, MYF(0));
keycache->block_mem= NULL;
}
if (keycache->block_root)
{
- my_free((gptr) keycache->block_root, MYF(0));
+ my_free((uchar*) keycache->block_root, MYF(0));
keycache->block_root= NULL;
}
my_errno= error;
@@ -480,12 +557,10 @@ err:
*/
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
- ulong use_mem, uint division_limit,
+ size_t use_mem, uint division_limit,
uint age_threshold)
{
int blocks;
- struct st_my_thread_var *thread;
- KEYCACHE_WQUEUE *wqueue;
DBUG_ENTER("resize_key_cache");
if (!keycache->key_cache_inited)
@@ -501,56 +576,88 @@ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
keycache_pthread_mutex_lock(&keycache->cache_lock);
#ifdef THREAD
- wqueue= &keycache->resize_queue;
- thread= my_thread_var;
- link_into_queue(wqueue, thread);
-
- while (wqueue->last_thread->next != thread)
+ /*
+ We may need to wait for another thread which is doing a resize
+ already. This cannot happen in the MySQL server though. It allows
+ one resizer only. In set_var.cc keycache->in_init is used to block
+ multiple attempts.
+ */
+ while (keycache->in_resize)
{
- keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
+ /* purecov: begin inspected */
+ wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
+ /* purecov: end */
}
#endif
- keycache->resize_in_flush= 1;
- if (flush_all_key_blocks(keycache))
+ /*
+ Mark the operation in progress. This blocks other threads from doing
+ a resize in parallel. It prohibits new blocks to enter the cache.
+ Read/write requests can bypass the cache during the flush phase.
+ */
+ keycache->in_resize= 1;
+
+ /* Need to flush only if keycache is enabled. */
+ if (keycache->can_be_used)
{
- /* TODO: if this happens, we should write a warning in the log file ! */
+ /* Start the flush phase. */
+ keycache->resize_in_flush= 1;
+
+ if (flush_all_key_blocks(keycache))
+ {
+ /* TODO: if this happens, we should write a warning in the log file ! */
+ keycache->resize_in_flush= 0;
+ blocks= 0;
+ keycache->can_be_used= 0;
+ goto finish;
+ }
+ DBUG_ASSERT(cache_empty(keycache));
+
+ /* End the flush phase. */
keycache->resize_in_flush= 0;
- blocks= 0;
- keycache->can_be_used= 0;
- goto finish;
}
- keycache->resize_in_flush= 0;
- keycache->can_be_used= 0;
+
#ifdef THREAD
+ /*
+ Some direct read/write operations (bypassing the cache) may still be
+ unfinished. Wait until they are done. If the key cache can be used,
+ direct I/O is done in increments of key_cache_block_size. That is,
+ every block is checked if it is in the cache. We need to wait for
+ pending I/O before re-initializing the cache, because we may change
+ the block size. Otherwise they could check for blocks at file
+ positions where the new block division has none. We do also want to
+ wait for I/O done when (if) the cache was disabled. It must not
+ run in parallel with normal cache operation.
+ */
while (keycache->cnt_for_resize_op)
- {
- KEYCACHE_DBUG_PRINT("resize_key_cache: wait",
- ("suspend thread %ld", thread->id));
- keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
- }
+ wait_on_queue(&keycache->waiting_for_resize_cnt, &keycache->cache_lock);
#else
KEYCACHE_DBUG_ASSERT(keycache->cnt_for_resize_op == 0);
#endif
+ /*
+ Free old cache structures, allocate new structures, and initialize
+ them. Note that the cache_lock mutex and the resize_queue are left
+ untouched. We do not lose the cache_lock and will release it only at
+ the end of this function.
+ */
end_key_cache(keycache, 0); /* Don't free mutex */
/* The following will work even if use_mem is 0 */
blocks= init_key_cache(keycache, key_cache_block_size, use_mem,
division_limit, age_threshold);
finish:
-#ifdef THREAD
- unlink_from_queue(wqueue, thread);
- /* Signal for the next resize request to proceeed if any */
- if (wqueue->last_thread)
- {
- KEYCACHE_DBUG_PRINT("resize_key_cache: signal",
- ("thread %ld", wqueue->last_thread->next->id));
- keycache_pthread_cond_signal(&wqueue->last_thread->next->suspend);
- }
-#endif
+ /*
+ Mark the resize finished. This allows other threads to start a
+ resize or to request new cache blocks.
+ */
+ keycache->in_resize= 0;
+
+ /* Signal waiting threads. */
+ release_whole_queue(&keycache->resize_queue);
+
keycache_pthread_mutex_unlock(&keycache->cache_lock);
- return blocks;
+ DBUG_RETURN(blocks);
}
@@ -569,18 +676,8 @@ static inline void inc_counter_for_resize_op(KEY_CACHE *keycache)
*/
static inline void dec_counter_for_resize_op(KEY_CACHE *keycache)
{
-#ifdef THREAD
- struct st_my_thread_var *last_thread;
- if (!--keycache->cnt_for_resize_op &&
- (last_thread= keycache->resize_queue.last_thread))
- {
- KEYCACHE_DBUG_PRINT("dec_counter_for_resize_op: signal",
- ("thread %ld", last_thread->next->id));
- keycache_pthread_cond_signal(&last_thread->next->suspend);
- }
-#else
- keycache->cnt_for_resize_op--;
-#endif
+ if (!--keycache->cnt_for_resize_op)
+ release_whole_queue(&keycache->waiting_for_resize_cnt);
}
/*
@@ -642,9 +739,9 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
{
if (keycache->block_mem)
{
- my_large_free((gptr) keycache->block_mem, MYF(0));
+ my_large_free((uchar*) keycache->block_mem, MYF(0));
keycache->block_mem= NULL;
- my_free((gptr) keycache->block_root, MYF(0));
+ my_free((uchar*) keycache->block_root, MYF(0));
keycache->block_root= NULL;
}
keycache->disk_blocks= -1;
@@ -671,6 +768,7 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
#ifdef THREAD
+
/*
Link a thread into double-linked queue of waiting threads.
@@ -692,6 +790,8 @@ static void link_into_queue(KEYCACHE_WQUEUE *wqueue,
struct st_my_thread_var *thread)
{
struct st_my_thread_var *last;
+
+ DBUG_ASSERT(!thread->next && !thread->prev);
if (! (last= wqueue->last_thread))
{
/* Queue is empty */
@@ -727,6 +827,7 @@ static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
struct st_my_thread_var *thread)
{
KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
+ DBUG_ASSERT(thread->next && thread->prev);
if (thread->next == thread)
/* The queue contains only one member */
wqueue->last_thread= NULL;
@@ -739,6 +840,13 @@ static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
thread->prev);
}
thread->next= NULL;
+#if !defined(DBUG_OFF)
+ /*
+ This makes it easier to see it's not in a chain during debugging.
+ And some DBUG_ASSERT() rely on it.
+ */
+ thread->prev= NULL;
+#endif
}
@@ -746,9 +854,9 @@ static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
Add a thread to single-linked queue of waiting threads
SYNOPSIS
- add_to_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be added to the queue
+ wait_on_queue()
+ wqueue Pointer to the queue structure.
+ mutex Cache_lock to acquire after awake.
RETURN VALUE
none
@@ -757,12 +865,23 @@ static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
Queue is represented by a circular list of the thread structures
The list is single-linked of the type (*next), accessed by a pointer
to the last element.
+
+ The function protects against stray signals by verifying that the
+ current thread is unlinked from the queue when awaking. However,
+ since several threads can wait for the same event, it might be
+ necessary for the caller of the function to check again if the
+ condition for awake is indeed matched.
*/
-static inline void add_to_queue(KEYCACHE_WQUEUE *wqueue,
- struct st_my_thread_var *thread)
+static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
+ pthread_mutex_t *mutex)
{
struct st_my_thread_var *last;
+ struct st_my_thread_var *thread= my_thread_var;
+
+ /* Add to queue. */
+ DBUG_ASSERT(!thread->next);
+ DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
if (! (last= wqueue->last_thread))
thread->next= thread;
else
@@ -771,6 +890,17 @@ static inline void add_to_queue(KEYCACHE_WQUEUE *wqueue,
last->next= thread;
}
wqueue->last_thread= thread;
+
+ /*
+ Wait until thread is removed from queue by the signalling thread.
+ The loop protects against stray signals.
+ */
+ do
+ {
+ KEYCACHE_DBUG_PRINT("wait", ("suspend thread %ld", thread->id));
+ keycache_pthread_cond_wait(&thread->suspend, mutex);
+ }
+ while (thread->next);
}
@@ -778,36 +908,47 @@ static inline void add_to_queue(KEYCACHE_WQUEUE *wqueue,
Remove all threads from queue signaling them to proceed
SYNOPSIS
- realease_queue()
- wqueue pointer to the queue structure
- thread pointer to the thread to be added to the queue
+ release_whole_queue()
+ wqueue pointer to the queue structure
RETURN VALUE
none
NOTES.
- See notes for add_to_queue
+ See notes for wait_on_queue().
When removed from the queue each thread is signaled via condition
variable thread->suspend.
*/
-static void release_queue(KEYCACHE_WQUEUE *wqueue)
+static void release_whole_queue(KEYCACHE_WQUEUE *wqueue)
{
- struct st_my_thread_var *last= wqueue->last_thread;
- struct st_my_thread_var *next= last->next;
+ struct st_my_thread_var *last;
+ struct st_my_thread_var *next;
struct st_my_thread_var *thread;
+
+ /* Queue may be empty. */
+ if (!(last= wqueue->last_thread))
+ return;
+
+ next= last->next;
do
{
thread=next;
- KEYCACHE_DBUG_PRINT("release_queue: signal", ("thread %ld", thread->id));
+ KEYCACHE_DBUG_PRINT("release_whole_queue: signal",
+ ("thread %ld", thread->id));
+ /* Signal the thread. */
keycache_pthread_cond_signal(&thread->suspend);
+ /* Take thread from queue. */
next=thread->next;
thread->next= NULL;
}
while (thread != last);
+
+ /* Now queue is definitely empty. */
wqueue->last_thread= NULL;
}
-#endif
+
+#endif /* THREAD */
/*
@@ -816,9 +957,19 @@ static void release_queue(KEYCACHE_WQUEUE *wqueue)
static inline void unlink_changed(BLOCK_LINK *block)
{
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
if (block->next_changed)
block->next_changed->prev_changed= block->prev_changed;
*block->prev_changed= block->next_changed;
+
+#if !defined(DBUG_OFF)
+ /*
+ This makes it easier to see it's not in a chain during debugging.
+ And some DBUG_ASSERT() rely on it.
+ */
+ block->next_changed= NULL;
+ block->prev_changed= NULL;
+#endif
}
@@ -828,6 +979,8 @@ static inline void unlink_changed(BLOCK_LINK *block)
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
{
+ DBUG_ASSERT(!block->next_changed);
+ DBUG_ASSERT(!block->prev_changed);
block->prev_changed= phead;
if ((block->next_changed= *phead))
(*phead)->prev_changed= &block->next_changed;
@@ -836,14 +989,37 @@ static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
/*
- Unlink a block from the chain of dirty/clean blocks, if it's asked for,
- and link it to the chain of clean blocks for the specified file
+ Link a block in a chain of clean blocks of a file.
+
+ SYNOPSIS
+ link_to_file_list()
+ keycache Key cache handle
+ block Block to relink
+ file File to be linked to
+ unlink If to unlink first
+
+ DESCRIPTION
+ Unlink a block from whichever chain it is linked in, if it's
+ asked for, and link it to the chain of clean blocks of the
+ specified file.
+
+ NOTE
+ Please do never set/clear BLOCK_CHANGED outside of
+ link_to_file_list() or link_to_changed_list().
+ You would risk to damage correct counting of changed blocks
+ and to find blocks in the wrong hash.
+
+ RETURN
+ void
*/
static void link_to_file_list(KEY_CACHE *keycache,
BLOCK_LINK *block, int file,
my_bool unlink_block)
{
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
+ DBUG_ASSERT(block->hash_link->file == file);
if (unlink_block)
unlink_changed(block);
link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
@@ -857,13 +1033,34 @@ static void link_to_file_list(KEY_CACHE *keycache,
/*
- Unlink a block from the chain of clean blocks for the specified
- file and link it to the chain of dirty blocks for this file
+ Re-link a block from the clean chain to the dirty chain of a file.
+
+ SYNOPSIS
+ link_to_changed_list()
+ keycache key cache handle
+ block block to relink
+
+ DESCRIPTION
+ Unlink a block from the chain of clean blocks of a file
+ and link it to the chain of dirty blocks of the same file.
+
+ NOTE
+ Please do never set/clear BLOCK_CHANGED outside of
+ link_to_file_list() or link_to_changed_list().
+ You would risk to damage correct counting of changed blocks
+ and to find blocks in the wrong hash.
+
+ RETURN
+ void
*/
-static inline void link_to_changed_list(KEY_CACHE *keycache,
- BLOCK_LINK *block)
+static void link_to_changed_list(KEY_CACHE *keycache,
+ BLOCK_LINK *block)
{
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
+
unlink_changed(block);
link_changed(block,
&keycache->changed_blocks[FILE_HASH(block->hash_link->file)]);
@@ -888,13 +1085,13 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
none
NOTES.
- The LRU chain is represented by a curcular list of block structures.
+ The LRU ring is represented by a circular list of block structures.
The list is double-linked of the type (**prev,*next) type.
- The LRU chain is divided into two parts - hot and warm.
+ The LRU ring is divided into two parts - hot and warm.
There are two pointers to access the last blocks of these two
parts. The beginning of the warm part follows right after the
end of the hot part.
- Only blocks of the warm part can be used for replacement.
+ Only blocks of the warm part can be used for eviction.
The first block from the beginning of this subchain is always
taken for eviction (keycache->last_used->next)
@@ -907,6 +1104,9 @@ static inline void link_to_changed_list(KEY_CACHE *keycache,
+----| beg |---->...----| end |----+
+------+ +------+ins
first for eviction
+
+ It is also possible that the block is selected for eviction and thus
+ not linked in the LRU ring.
*/
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
@@ -915,7 +1115,12 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
BLOCK_LINK *ins;
BLOCK_LINK **pins;
- KEYCACHE_DBUG_ASSERT(! (block->hash_link && block->hash_link->requests));
+ DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
+ DBUG_ASSERT(!block->requests);
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ DBUG_ASSERT(!block->next_used);
+ DBUG_ASSERT(!block->prev_used);
#ifdef THREAD
if (!hot && keycache->waiting_for_block.last_thread)
{
@@ -944,6 +1149,29 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
}
while (thread != last_thread);
hash_link->block= block;
+ /*
+ NOTE: We assigned the block to the hash_link and signalled the
+ requesting thread(s). But it is possible that other threads runs
+ first. These threads see the hash_link assigned to a block which
+ is assigned to another hash_link and not marked BLOCK_IN_SWITCH.
+ This can be a problem for functions that do not select the block
+ via its hash_link: flush and free. They do only see a block which
+ is in a "normal" state and don't know that it will be evicted soon.
+
+ We cannot set BLOCK_IN_SWITCH here because only one of the
+ requesting threads must handle the eviction. All others must wait
+ for it to complete. If we set the flag here, the threads would not
+ know who is in charge of the eviction. Without the flag, the first
+ thread takes the stick and sets the flag.
+
+ But we need to note in the block that is has been selected for
+ eviction. It must not be freed. The evicting thread will not
+ expect the block in the free list. Before freeing we could also
+ check if block->requests > 1. But I think including another flag
+ in the check of block->status is slightly more efficient and
+ probably easier to read.
+ */
+ block->status|= BLOCK_IN_EVICTION;
KEYCACHE_THREAD_TRACE("link_block: after signaling");
#if defined(KEYCACHE_DEBUG)
KEYCACHE_DBUG_PRINT("link_block",
@@ -970,7 +1198,7 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
}
else
{
- /* The LRU chain is empty */
+ /* The LRU ring is empty. Let the block point to itself. */
keycache->used_last= keycache->used_ins= block->next_used= block;
block->prev_used= &block->next_used;
}
@@ -1004,6 +1232,13 @@ static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
{
+ DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
+ DBUG_ASSERT(!block->requests);
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ DBUG_ASSERT(block->next_used && block->prev_used &&
+ (block->next_used->prev_used == &block->next_used) &&
+ (*block->prev_used == block));
if (block->next_used == block)
/* The list contains only one member */
keycache->used_last= keycache->used_ins= NULL;
@@ -1017,6 +1252,13 @@ static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
}
block->next_used= NULL;
+#if !defined(DBUG_OFF)
+ /*
+ This makes it easier to see it's not in a chain during debugging.
+ And some DBUG_ASSERT() rely on it.
+ */
+ block->prev_used= NULL;
+#endif
KEYCACHE_THREAD_TRACE("unlink_block");
#if defined(KEYCACHE_DEBUG)
@@ -1031,12 +1273,27 @@ static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
/*
- Register requests for a block
+ Register requests for a block.
+
+ SYNOPSIS
+ reg_requests()
+ keycache Pointer to a key cache data structure.
+ block Pointer to the block to register a request on.
+ count Number of requests. Always 1.
+
+ NOTE
+ The first request unlinks the block from the LRU ring. This means
+ that it is protected against eveiction.
+
+ RETURN
+ void
*/
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
{
- if (! block->requests)
- /* First request for the block unlinks it */
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT(block->hash_link);
+
+ if (!block->requests)
unlink_block(keycache, block);
block->requests+=count;
}
@@ -1056,7 +1313,7 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
none
NOTES.
- Every linking to the LRU chain decrements by one a special block
+ Every linking to the LRU ring decrements by one a special block
counter (if it's positive). If the at_end parameter is TRUE the block is
added either at the end of warm sub-chain or at the end of hot sub-chain.
It is added to the hot subchain if its counter is zero and number of
@@ -1069,11 +1326,20 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
At the same time the block at the very beginning of the hot subchain
might be moved to the beginning of the warm subchain if it stays untouched
for a too long time (this time is determined by parameter age_threshold).
+
+ It is also possible that the block is selected for eviction and thus
+ not linked in the LRU ring.
*/
static void unreg_request(KEY_CACHE *keycache,
BLOCK_LINK *block, int at_end)
{
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
+ DBUG_ASSERT(block->requests);
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ DBUG_ASSERT(!block->next_used);
+ DBUG_ASSERT(!block->prev_used);
if (! --block->requests)
{
my_bool hot;
@@ -1092,9 +1358,22 @@ static void unreg_request(KEY_CACHE *keycache,
link_block(keycache, block, hot, (my_bool)at_end);
block->last_hit_time= keycache->keycache_time;
keycache->keycache_time++;
+ /*
+ At this place, the block might be in the LRU ring or not. If an
+ evicter was waiting for a block, it was selected for eviction and
+ not linked in the LRU ring.
+ */
+ /*
+ Check if we should link a hot block to the warm block sub-chain.
+ It is possible that we select the same block as above. But it can
+ also be another block. In any case a block from the LRU ring is
+ selected. In other words it works even if the above block was
+ selected for eviction and not linked in the LRU ring. Since this
+ happens only if the LRU ring is empty, the block selected below
+ would be NULL and the rest of the function skipped.
+ */
block= keycache->used_ins;
- /* Check if we should link a hot block to the warm block */
if (block && keycache->keycache_time - block->last_hit_time >
keycache->age_threshold)
{
@@ -1115,10 +1394,20 @@ static void unreg_request(KEY_CACHE *keycache,
Remove a reader of the page in block
*/
-static inline void remove_reader(BLOCK_LINK *block)
+static void remove_reader(BLOCK_LINK *block)
{
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ DBUG_ASSERT(!block->next_used);
+ DBUG_ASSERT(!block->prev_used);
+ DBUG_ASSERT(block->hash_link->requests);
+#ifdef THREAD
if (! --block->hash_link->requests && block->condvar)
keycache_pthread_cond_signal(block->condvar);
+#else
+ --block->hash_link->requests;
+#endif
}
@@ -1127,15 +1416,28 @@ static inline void remove_reader(BLOCK_LINK *block)
signals on its termination
*/
-static inline void wait_for_readers(KEY_CACHE *keycache, BLOCK_LINK *block)
+static void wait_for_readers(KEY_CACHE *keycache,
+ BLOCK_LINK *block)
{
#ifdef THREAD
struct st_my_thread_var *thread= my_thread_var;
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
+ BLOCK_CHANGED)));
+ DBUG_ASSERT(block->hash_link);
+ DBUG_ASSERT(block->hash_link->block == block);
+ /* Linked in file_blocks or changed_blocks hash. */
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ /* Not linked in LRU ring. */
+ DBUG_ASSERT(!block->next_used);
+ DBUG_ASSERT(!block->prev_used);
while (block->hash_link->requests)
{
KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
("suspend thread %ld block %u",
thread->id, BLOCK_NUMBER(block)));
+ /* There must be no other waiter. We have no queue here. */
+ DBUG_ASSERT(!block->condvar);
block->condvar= &thread->suspend;
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
block->condvar= NULL;
@@ -1224,7 +1526,6 @@ static HASH_LINK *get_hash_link(KEY_CACHE *keycache,
int file, my_off_t filepos)
{
reg1 HASH_LINK *hash_link, **start;
- KEYCACHE_PAGE page;
#if defined(KEYCACHE_DEBUG)
int cnt;
#endif
@@ -1279,6 +1580,7 @@ restart:
#ifdef THREAD
/* Wait for a free hash link */
struct st_my_thread_var *thread= my_thread_var;
+ KEYCACHE_PAGE page;
KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
page.file= file;
page.filepos= filepos;
@@ -1364,77 +1666,308 @@ static BLOCK_LINK *find_key_block(KEY_CACHE *keycache,
#endif
restart:
- /* Find the hash link for the requested page (file, filepos) */
+ /*
+ If the flush phase of a resize operation fails, the cache is left
+ unusable. This will be detected only after "goto restart".
+ */
+ if (!keycache->can_be_used)
+ DBUG_RETURN(0);
+
+ /*
+ Find the hash_link for the requested file block (file, filepos). We
+ do always get a hash_link here. It has registered our request so
+ that no other thread can use it for another file block until we
+ release the request (which is done by remove_reader() usually). The
+ hash_link can have a block assigned to it or not. If there is a
+ block, it may be assigned to this hash_link or not. In cases where a
+ block is evicted from the cache, it is taken from the LRU ring and
+ referenced by the new hash_link. But the block can still be assigned
+ to its old hash_link for some time if it needs to be flushed first,
+ or if there are other threads still reading it.
+
+ Summary:
+ hash_link is always returned.
+ hash_link->block can be:
+ - NULL or
+ - not assigned to this hash_link or
+ - assigned to this hash_link. If assigned, the block can have
+ - invalid data (when freshly assigned) or
+ - valid data. Valid data can be
+ - changed over the file contents (dirty) or
+ - not changed (clean).
+ */
hash_link= get_hash_link(keycache, file, filepos);
+ DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
page_status= -1;
if ((block= hash_link->block) &&
block->hash_link == hash_link && (block->status & BLOCK_READ))
+ {
+ /* Assigned block with valid (changed or unchanged) contents. */
page_status= PAGE_READ;
+ }
+ /*
+ else (page_status == -1)
+ - block == NULL or
+ - block not assigned to this hash_link or
+ - block assigned but not yet read from file (invalid data).
+ */
- if (wrmode && keycache->resize_in_flush)
+ if (keycache->in_resize)
{
- /* This is a write request during the flush phase of a resize operation */
+ /* This is a request during a resize operation */
- if (page_status != PAGE_READ)
+ if (!block)
{
- /* We don't need the page in the cache: we are going to write on disk */
+ struct st_my_thread_var *thread;
+
+ /*
+ The file block is not in the cache. We don't need it in the
+ cache: we are going to read or write directly to file. Cancel
+ the request. We can simply decrement hash_link->requests because
+ we did not release cache_lock since increasing it. So no other
+ thread can wait for our request to become released.
+ */
+ if (hash_link->requests == 1)
+ {
+ /*
+ We are the only one to request this hash_link (this file/pos).
+ Free the hash_link.
+ */
+ hash_link->requests--;
+ unlink_hash(keycache, hash_link);
+ DBUG_RETURN(0);
+ }
+
+ /*
+ More requests on the hash_link. Someone tries to evict a block
+ for this hash_link (could have started before resizing started).
+ This means that the LRU ring is empty. Otherwise a block could
+ be assigned immediately. Behave like a thread that wants to
+ evict a block for this file/pos. Add to the queue of threads
+ waiting for a block. Wait until there is one assigned.
+
+ Refresh the request on the hash-link so that it cannot be reused
+ for another file/pos.
+ */
+ thread= my_thread_var;
+ thread->opt_info= (void *) hash_link;
+ link_into_queue(&keycache->waiting_for_block, thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("find_key_block: wait",
+ ("suspend thread %ld", thread->id));
+ keycache_pthread_cond_wait(&thread->suspend,
+ &keycache->cache_lock);
+ } while (thread->next);
+ thread->opt_info= NULL;
+ /*
+ A block should now be assigned to the hash_link. But it may
+ still need to be evicted. Anyway, we should re-check the
+ situation. page_status must be set correctly.
+ */
hash_link->requests--;
- unlink_hash(keycache, hash_link);
- return 0;
+ goto restart;
+ } /* end of if (!block) */
+
+ /*
+ There is a block for this file/pos in the cache. Register a
+ request on it. This unlinks it from the LRU ring (if it is there)
+ and hence protects it against eviction (if not already in
+ eviction). We need this for returning the block to the caller, for
+ calling remove_reader() (for debugging purposes), and for calling
+ free_block(). The only case where we don't need the request is if
+ the block is in eviction. In that case we have to unregister the
+ request later.
+ */
+ reg_requests(keycache, block, 1);
+
+ if (page_status != PAGE_READ)
+ {
+ /*
+ - block not assigned to this hash_link or
+ - block assigned but not yet read from file (invalid data).
+
+ This must be a block in eviction. It will be read soon. We need
+ to wait here until this happened. Otherwise the caller could
+ access a wrong block or a block which is in read. While waiting
+ we cannot lose hash_link nor block. We have registered a request
+ on the hash_link. Everything can happen to the block but changes
+ in the hash_link -> block relationship. In other words:
+ everything can happen to the block but free or another completed
+ eviction.
+
+ Note that we bahave like a secondary requestor here. We just
+ cannot return with PAGE_WAIT_TO_BE_READ. This would work for
+ read requests and writes on dirty blocks that are not in flush
+ only. Waiting here on COND_FOR_REQUESTED works in all
+ situations.
+ */
+ DBUG_ASSERT(((block->hash_link != hash_link) &&
+ (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
+ ((block->hash_link == hash_link) &&
+ !(block->status & BLOCK_READ)));
+ wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
+ /*
+ Here we can trust that the block has been assigned to this
+ hash_link (block->hash_link == hash_link) and read into the
+ buffer (BLOCK_READ). The worst things possible here are that the
+ block is in free (BLOCK_REASSIGNED). But the block is still
+ assigned to the hash_link. The freeing thread waits until we
+ release our request on the hash_link. The block must not be
+ again in eviction because we registered an request on it before
+ starting to wait.
+ */
+ DBUG_ASSERT(block->hash_link == hash_link);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
}
- if (!(block->status & BLOCK_IN_FLUSH))
+ /*
+ The block is in the cache. Assigned to the hash_link. Valid data.
+ Note that in case of page_st == PAGE_READ, the block can be marked
+ for eviction. In any case it can be marked for freeing.
+ */
+
+ if (!wrmode)
+ {
+ /* A reader can just read the block. */
+ *page_st= PAGE_READ;
+ DBUG_ASSERT((hash_link->file == file) &&
+ (hash_link->diskpos == filepos) &&
+ (block->hash_link == hash_link));
+ DBUG_RETURN(block);
+ }
+
+ /*
+ This is a writer. No two writers for the same block can exist.
+ This must be assured by locks outside of the key cache.
+ */
+ DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
+
+ while (block->status & BLOCK_IN_FLUSH)
{
- hash_link->requests--;
/*
- Remove block to invalidate the page in the block buffer
- as we are going to write directly on disk.
- Although we have an exlusive lock for the updated key part
- the control can be yieded by the current thread as we might
+ Wait until the block is flushed to file. Do not release the
+ request on the hash_link yet to prevent that the block is freed
+ or reassigned while we wait. While we wait, several things can
+ happen to the block, including another flush. But the block
+ cannot be reassigned to another hash_link until we release our
+ request on it. But it can be marked BLOCK_REASSIGNED from free
+ or eviction, while they wait for us to release the hash_link.
+ */
+ wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
+ /*
+ If the flush phase failed, the resize could have finished while
+ we waited here.
+ */
+ if (!keycache->in_resize)
+ {
+ remove_reader(block);
+ unreg_request(keycache, block, 1);
+ goto restart;
+ }
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
+ DBUG_ASSERT(block->hash_link == hash_link);
+ }
+
+ if (block->status & BLOCK_CHANGED)
+ {
+ /*
+ We want to write a block with changed contents. If the cache
+ block size is bigger than the callers block size (e.g. MyISAM),
+ the caller may replace part of the block only. Changes of the
+ other part of the block must be preserved. Since the block has
+ not yet been selected for flush, we can still add our changes.
+ */
+ *page_st= PAGE_READ;
+ DBUG_ASSERT((hash_link->file == file) &&
+ (hash_link->diskpos == filepos) &&
+ (block->hash_link == hash_link));
+ DBUG_RETURN(block);
+ }
+
+ /*
+ This is a write request for a clean block. We do not want to have
+ new dirty blocks in the cache while resizing. We will free the
+ block and write directly to file. If the block is in eviction or
+ in free, we just let it go.
+
+ Unregister from the hash_link. This must be done before freeing
+ the block. And it must be done if not freeing the block. Because
+ we could have waited above, we need to call remove_reader(). Other
+ threads could wait for us to release our request on the hash_link.
+ */
+ remove_reader(block);
+
+ /* If the block is not in eviction and not in free, we can free it. */
+ if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_REASSIGNED)))
+ {
+ /*
+ Free block as we are going to write directly to file.
+ Although we have an exlusive lock for the updated key part,
+ the control can be yielded by the current thread as we might
have unfinished readers of other key parts in the block
buffer. Still we are guaranteed not to have any readers
of the key part we are writing into until the block is
- removed from the cache as we set the BLOCL_REASSIGNED
+ removed from the cache as we set the BLOCK_REASSIGNED
flag (see the code below that handles reading requests).
*/
free_block(keycache, block);
- return 0;
}
- /* Wait intil the page is flushed on disk */
- hash_link->requests--;
+ else
{
-#ifdef THREAD
- struct st_my_thread_var *thread= my_thread_var;
- add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
- do
- {
- KEYCACHE_DBUG_PRINT("find_key_block: wait",
- ("suspend thread %ld", thread->id));
- keycache_pthread_cond_wait(&thread->suspend,
- &keycache->cache_lock);
- }
- while(thread->next);
-#else
- KEYCACHE_DBUG_ASSERT(0);
/*
- Given the use of "resize_in_flush", it seems impossible
- that this whole branch is ever entered in single-threaded case
- because "(wrmode && keycache->resize_in_flush)" cannot be true.
- TODO: Check this, and then put the whole branch into the
- "#ifdef THREAD" guard.
+ The block will be evicted/freed soon. Don't touch it in any way.
+ Unregister the request that we registered above.
*/
-#endif
+ unreg_request(keycache, block, 1);
+
+ /*
+ The block is still assigned to the hash_link (the file/pos that
+ we are going to write to). Wait until the eviction/free is
+ complete. Otherwise the direct write could complete before all
+ readers are done with the block. So they could read outdated
+ data.
+
+ Since we released our request on the hash_link, it can be reused
+ for another file/pos. Hence we cannot just check for
+ block->hash_link == hash_link. As long as the resize is
+ proceeding the block cannot be reassigned to the same file/pos
+ again. So we can terminate the loop when the block is no longer
+ assigned to this file/pos.
+ */
+ do
+ {
+ wait_on_queue(&block->wqueue[COND_FOR_SAVED],
+ &keycache->cache_lock);
+ /*
+ If the flush phase failed, the resize could have finished
+ while we waited here.
+ */
+ if (!keycache->in_resize)
+ goto restart;
+ } while (block->hash_link &&
+ (block->hash_link->file == file) &&
+ (block->hash_link->diskpos == filepos));
}
- /* Invalidate page in the block if it has not been done yet */
- if (block->status)
- free_block(keycache, block);
- return 0;
+ DBUG_RETURN(0);
}
if (page_status == PAGE_READ &&
- (block->status & (BLOCK_IN_SWITCH | BLOCK_REASSIGNED)))
+ (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_REASSIGNED)))
{
- /* This is a request for a page to be removed from cache */
+ /*
+ This is a request for a block to be removed from cache. The block
+ is assigned to this hash_link and contains valid data, but is
+ marked for eviction or to be freed. Possible reasons why it has
+ not yet been evicted/freed can be a flush before reassignment
+ (BLOCK_IN_SWITCH), readers of the block have not finished yet
+ (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
+ the block has been selected for it (BLOCK_IN_EVICTION).
+ */
KEYCACHE_DBUG_PRINT("find_key_block",
("request for old page in block %u "
@@ -1445,43 +1978,58 @@ restart:
all others are to be suspended, then resubmitted
*/
if (!wrmode && !(block->status & BLOCK_REASSIGNED))
+ {
+ /*
+ This is a read request and the block not yet reassigned. We can
+ register our request and proceed. This unlinks the block from
+ the LRU ring and protects it against eviction.
+ */
reg_requests(keycache, block, 1);
+ }
else
{
+ /*
+ Either this is a write request for a block that is in eviction
+ or in free. We must not use it any more. Instead we must evict
+ another block. But we cannot do this before the eviction/free is
+ done. Otherwise we would find the same hash_link + block again
+ and again.
+
+ Or this is a read request for a block in eviction/free that does
+ not require a flush, but waits for readers to finish with the
+ block. We do not read this block to let the eviction/free happen
+ as soon as possible. Again we must wait so that we don't find
+ the same hash_link + block again and again.
+ */
+ DBUG_ASSERT(hash_link->requests);
hash_link->requests--;
KEYCACHE_DBUG_PRINT("find_key_block",
("request waiting for old page to be saved"));
- {
-#ifdef THREAD
- struct st_my_thread_var *thread= my_thread_var;
- /* Put the request into the queue of those waiting for the old page */
- add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
- /* Wait until the request can be resubmitted */
- do
- {
- KEYCACHE_DBUG_PRINT("find_key_block: wait",
- ("suspend thread %ld", thread->id));
- keycache_pthread_cond_wait(&thread->suspend,
- &keycache->cache_lock);
- }
- while(thread->next);
-#else
- KEYCACHE_DBUG_ASSERT(0);
- /* No parallel requests in single-threaded case */
-#endif
- }
+ wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
KEYCACHE_DBUG_PRINT("find_key_block",
("request for old page resubmitted"));
- /* Resubmit the request */
+ /*
+ The block is no longer assigned to this hash_link.
+ Get another one.
+ */
goto restart;
}
}
else
{
- /* This is a request for a new page or for a page not to be removed */
+ /*
+ This is a request for a new block or for a block not to be removed.
+ Either
+ - block == NULL or
+ - block not assigned to this hash_link or
+ - block assigned but not yet read from file,
+ or
+ - block assigned with valid (changed or unchanged) data and
+ - it will not be reassigned/freed.
+ */
if (! block)
{
- /* No block is assigned for the page yet */
+ /* No block is assigned to the hash_link yet. */
if (keycache->blocks_unused)
{
if (keycache->free_block_list)
@@ -1494,24 +2042,33 @@ restart:
else
{
/* There are some never used blocks, take first of them */
+ DBUG_ASSERT(keycache->blocks_used <
+ (ulong) keycache->disk_blocks);
block= &keycache->block_root[keycache->blocks_used];
block->buffer= ADD_TO_PTR(keycache->block_mem,
((ulong) keycache->blocks_used*
keycache->key_cache_block_size),
- byte*);
+ uchar*);
keycache->blocks_used++;
+ DBUG_ASSERT(!block->next_used);
}
+ DBUG_ASSERT(!block->prev_used);
+ DBUG_ASSERT(!block->next_changed);
+ DBUG_ASSERT(!block->prev_changed);
+ DBUG_ASSERT(!block->hash_link);
+ DBUG_ASSERT(!block->status);
+ DBUG_ASSERT(!block->requests);
keycache->blocks_unused--;
- block->status= 0;
+ block->status= BLOCK_IN_USE;
block->length= 0;
block->offset= keycache->key_cache_block_size;
block->requests= 1;
block->temperature= BLOCK_COLD;
block->hits_left= init_hits_left;
block->last_hit_time= 0;
- link_to_file_list(keycache, block, file, 0);
block->hash_link= hash_link;
hash_link->block= block;
+ link_to_file_list(keycache, block, file, 0);
page_status= PAGE_TO_BE_READ;
KEYCACHE_DBUG_PRINT("find_key_block",
("got free or never used block %u",
@@ -1519,17 +2076,26 @@ restart:
}
else
{
- /* There are no never used blocks, use a block from the LRU chain */
-
- /*
- Wait until a new block is added to the LRU chain;
- several threads might wait here for the same page,
- all of them must get the same block
+ /*
+ There are no free blocks and no never used blocks, use a block
+ from the LRU ring.
*/
#ifdef THREAD
if (! keycache->used_last)
{
+ /*
+ The LRU ring is empty. Wait until a new block is added to
+ it. Several threads might wait here for the same hash_link,
+ all of them must get the same block. While waiting for a
+ block, after a block is selected for this hash_link, other
+ threads can run first before this one awakes. During this
+ time interval other threads find this hash_link pointing to
+ the block, which is still assigned to another hash_link. In
+ this case the block is not marked BLOCK_IN_SWITCH yet, but
+ it is marked BLOCK_IN_EVICTION.
+ */
+
struct st_my_thread_var *thread= my_thread_var;
thread->opt_info= (void *) hash_link;
link_into_queue(&keycache->waiting_for_block, thread);
@@ -1542,24 +2108,50 @@ restart:
}
while (thread->next);
thread->opt_info= NULL;
+ /* Assert that block has a request registered. */
+ DBUG_ASSERT(hash_link->block->requests);
+ /* Assert that block is not in LRU ring. */
+ DBUG_ASSERT(!hash_link->block->next_used);
+ DBUG_ASSERT(!hash_link->block->prev_used);
}
#else
KEYCACHE_DBUG_ASSERT(keycache->used_last);
#endif
+ /*
+ If we waited above, hash_link->block has been assigned by
+ link_block(). Otherwise it is still NULL. In the latter case
+ we need to grab a block from the LRU ring ourselves.
+ */
block= hash_link->block;
if (! block)
{
- /*
- Take the first block from the LRU chain
- unlinking it from the chain
- */
+ /* Select the last block from the LRU ring. */
block= keycache->used_last->next_used;
block->hits_left= init_hits_left;
block->last_hit_time= 0;
- reg_requests(keycache, block,1);
hash_link->block= block;
+ /*
+ Register a request on the block. This unlinks it from the
+ LRU ring and protects it against eviction.
+ */
+ DBUG_ASSERT(!block->requests);
+ reg_requests(keycache, block,1);
+ /*
+ We do not need to set block->status|= BLOCK_IN_EVICTION here
+ because we will set block->status|= BLOCK_IN_SWITCH
+ immediately without releasing the lock in between. This does
+ also support debugging. When looking at the block, one can
+ see if the block has been selected by link_block() after the
+ LRU ring was empty, or if it was grabbed directly from the
+ LRU ring in this branch.
+ */
}
+ /*
+ If we had to wait above, there is a small chance that another
+ thread grabbed this block for the same file block already. But
+ in most cases the first condition is true.
+ */
if (block->hash_link != hash_link &&
! (block->status & BLOCK_IN_SWITCH) )
{
@@ -1574,44 +2166,117 @@ restart:
/* The block contains a dirty page - push it out of the cache */
KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
+ if (block->status & BLOCK_IN_FLUSH)
+ {
+ /*
+ The block is marked for flush. If we do not wait here,
+ it could happen that we write the block, reassign it to
+ another file block, then, before the new owner can read
+ the new file block, the flusher writes the cache block
+ (which still has the old contents) to the new file block!
+ */
+ wait_on_queue(&block->wqueue[COND_FOR_SAVED],
+ &keycache->cache_lock);
+ /*
+ The block is marked BLOCK_IN_SWITCH. It should be left
+ alone except for reading. No free, no write.
+ */
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
+ BLOCK_CHANGED |
+ BLOCK_FOR_UPDATE)));
+ }
+ else
+ {
+ block->status|= BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE;
+ /*
+ BLOCK_IN_EVICTION may be true or not. Other flags must
+ have a fixed value.
+ */
+ DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
+ (BLOCK_READ | BLOCK_IN_SWITCH |
+ BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
+ BLOCK_CHANGED | BLOCK_IN_USE));
+ DBUG_ASSERT(block->hash_link);
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
- /*
- The call is thread safe because only the current
- thread might change the block->hash_link value
- */
- error= my_pwrite(block->hash_link->file,
- block->buffer+block->offset,
- block->length - block->offset,
- block->hash_link->diskpos+ block->offset,
- MYF(MY_NABP | MY_WAIT_IF_FULL));
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- keycache->global_cache_write++;
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ /*
+ The call is thread safe because only the current
+ thread might change the block->hash_link value
+ */
+ error= my_pwrite(block->hash_link->file,
+ block->buffer+block->offset,
+ block->length - block->offset,
+ block->hash_link->diskpos+ block->offset,
+ MYF(MY_NABP | MY_WAIT_IF_FULL));
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+
+ /* Block status must not have changed. */
+ DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
+ (BLOCK_READ | BLOCK_IN_SWITCH |
+ BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
+ BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
+ keycache->global_cache_write++;
+ }
}
block->status|= BLOCK_REASSIGNED;
+ /*
+ The block comes from the LRU ring. It must have a hash_link
+ assigned.
+ */
+ DBUG_ASSERT(block->hash_link);
if (block->hash_link)
{
/*
+ All pending requests for this page must be resubmitted.
+ This must be done before waiting for readers. They could
+ wait for the flush to complete. And we must also do it
+ after the wait. Flushers might try to free the block while
+ we wait. They would wait until the reassignment is
+ complete. Also the block status must reflect the correct
+ situation: The block is not changed nor in flush any more.
+ Note that we must not change the BLOCK_CHANGED flag
+ outside of link_to_file_list() so that it is always in the
+ correct queue and the *blocks_changed counters are
+ correct.
+ */
+ block->status&= ~(BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE);
+ link_to_file_list(keycache, block, block->hash_link->file, 1);
+ release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
+ /*
+ The block is still assigned to its old hash_link.
Wait until all pending read requests
for this page are executed
(we could have avoided this waiting, if we had read
a page in the cache in a sweep, without yielding control)
*/
wait_for_readers(keycache, block);
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
+ block->prev_changed);
+ /* The reader must not have been a writer. */
+ DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
- /* Remove the hash link for this page from the hash table */
+ /* Wake flushers that might have found the block in between. */
+ release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
+
+ /* Remove the hash link for the old file block from the hash. */
unlink_hash(keycache, block->hash_link);
- /* All pending requests for this page must be resubmitted */
- if (block->wqueue[COND_FOR_SAVED].last_thread)
- release_queue(&block->wqueue[COND_FOR_SAVED]);
+
+ /*
+ For sanity checks link_to_file_list() asserts that block
+ and hash_link refer to each other. Hence we need to assign
+ the hash_link first, but then we would not know if it was
+ linked before. Hence we would not know if to unlink it. So
+ unlink it here and call link_to_file_list(..., FALSE).
+ */
+ unlink_changed(block);
}
- link_to_file_list(keycache, block, file,
- (my_bool)(block->hash_link ? 1 : 0));
- block->status= error? BLOCK_ERROR : 0;
+ block->status= error ? BLOCK_ERROR : BLOCK_IN_USE ;
block->length= 0;
block->offset= keycache->key_cache_block_size;
block->hash_link= hash_link;
+ link_to_file_list(keycache, block, file, 0);
page_status= PAGE_TO_BE_READ;
KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
@@ -1619,7 +2284,20 @@ restart:
}
else
{
- /* This is for secondary requests for a new page only */
+ /*
+ Either (block->hash_link == hash_link),
+ or (block->status & BLOCK_IN_SWITCH).
+
+ This is for secondary requests for a new file block only.
+ Either it is already assigned to the new hash_link meanwhile
+ (if we had to wait due to empty LRU), or it is already in
+ eviction by another thread. Since this block has been
+ grabbed from the LRU ring and attached to this hash_link,
+ another thread cannot grab the same block from the LRU ring
+ anymore. If the block is in eviction already, it must become
+ attached to the same hash_link and as such destined for the
+ same file block.
+ */
KEYCACHE_DBUG_PRINT("find_key_block",
("block->hash_link: %p hash_link: %p "
"block->status: %u", block->hash_link,
@@ -1629,10 +2307,35 @@ restart:
PAGE_READ : PAGE_WAIT_TO_BE_READ);
}
}
- keycache->global_cache_read++;
}
else
{
+ /*
+ Block is not NULL. This hash_link points to a block.
+ Either
+ - block not assigned to this hash_link (yet) or
+ - block assigned but not yet read from file,
+ or
+ - block assigned with valid (changed or unchanged) data and
+ - it will not be reassigned/freed.
+
+ The first condition means hash_link points to a block in
+ eviction. This is not necessarily marked by BLOCK_IN_SWITCH yet.
+ But then it is marked BLOCK_IN_EVICTION. See the NOTE in
+ link_block(). In both cases it is destined for this hash_link
+ and its file block address. When this hash_link got its block
+ address, the block was removed from the LRU ring and cannot be
+ selected for eviction (for another hash_link) again.
+
+ Register a request on the block. This is another protection
+ against eviction.
+ */
+ DBUG_ASSERT(((block->hash_link != hash_link) &&
+ (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
+ ((block->hash_link == hash_link) &&
+ !(block->status & BLOCK_READ)) ||
+ ((block->status & BLOCK_READ) &&
+ !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
reg_requests(keycache, block, 1);
KEYCACHE_DBUG_PRINT("find_key_block",
("block->hash_link: %p hash_link: %p "
@@ -1645,6 +2348,16 @@ restart:
}
KEYCACHE_DBUG_ASSERT(page_status != -1);
+ /* Same assert basically, but be very sure. */
+ KEYCACHE_DBUG_ASSERT(block);
+ /* Assert that block has a request and is not in LRU ring. */
+ DBUG_ASSERT(block->requests);
+ DBUG_ASSERT(!block->next_used);
+ DBUG_ASSERT(!block->prev_used);
+ /* Assert that we return the correct block. */
+ DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
+ ((block->hash_link->file == file) &&
+ (block->hash_link->diskpos == filepos)));
*page_st=page_status;
KEYCACHE_DBUG_PRINT("find_key_block",
("fd: %d pos: %lu block->status: %u page_status: %u",
@@ -1696,13 +2409,22 @@ static void read_block(KEY_CACHE *keycache,
if (primary)
{
/*
- This code is executed only by threads
- that submitted primary requests
+ This code is executed only by threads that submitted primary
+ requests. Until block->status contains BLOCK_READ, all other
+ request for the block become secondary requests. For a primary
+ request the block must be properly initialized.
*/
+ DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
+ fail_block(block));
+ DBUG_ASSERT((block->length == 0) || fail_block(block));
+ DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
+ fail_block(block));
+ DBUG_ASSERT((block->requests > 0) || fail_block(block));
KEYCACHE_DBUG_PRINT("read_block",
("page to be read by primary request"));
+ keycache->global_cache_read++;
/* Page is not in buffer yet, is to be read from disk */
keycache_pthread_mutex_unlock(&keycache->cache_lock);
/*
@@ -1712,45 +2434,50 @@ static void read_block(KEY_CACHE *keycache,
got_length= my_pread(block->hash_link->file, block->buffer,
read_length, block->hash_link->diskpos, MYF(0));
keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /*
+ The block can now have been marked for free (in case of
+ FLUSH_RELEASE). Otherwise the state must be unchanged.
+ */
+ DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
+ BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
+ fail_block(block));
+ DBUG_ASSERT((block->length == 0) || fail_block(block));
+ DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
+ fail_block(block));
+ DBUG_ASSERT((block->requests > 0) || fail_block(block));
+
if (got_length < min_length)
block->status|= BLOCK_ERROR;
else
{
- block->status= BLOCK_READ;
+ block->status|= BLOCK_READ;
block->length= got_length;
+ /*
+ Do not set block->offset here. If this block is marked
+ BLOCK_CHANGED later, we want to flush only the modified part. So
+ only a writer may set block->offset down from
+ keycache->key_cache_block_size.
+ */
}
KEYCACHE_DBUG_PRINT("read_block",
("primary request: new page in cache"));
/* Signal that all pending requests for this page now can be processed */
- if (block->wqueue[COND_FOR_REQUESTED].last_thread)
- release_queue(&block->wqueue[COND_FOR_REQUESTED]);
+ release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
}
else
{
/*
- This code is executed only by threads
- that submitted secondary requests
+ This code is executed only by threads that submitted secondary
+ requests. At this point it could happen that the cache block is
+ not yet assigned to the hash_link for the requested file block.
+ But at awake from the wait this should be the case. Unfortunately
+ we cannot assert this here because we do not know the hash_link
+ for the requested file block nor the file and position. So we have
+ to assert this in the caller.
*/
KEYCACHE_DBUG_PRINT("read_block",
("secondary request waiting for new page to be read"));
- {
-#ifdef THREAD
- struct st_my_thread_var *thread= my_thread_var;
- /* Put the request into a queue and wait until it can be processed */
- add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread);
- do
- {
- KEYCACHE_DBUG_PRINT("read_block: wait",
- ("suspend thread %ld", thread->id));
- keycache_pthread_cond_wait(&thread->suspend,
- &keycache->cache_lock);
- }
- while (thread->next);
-#else
- KEYCACHE_DBUG_ASSERT(0);
- /* No parallel requests in single-threaded case */
-#endif
- }
+ wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
KEYCACHE_DBUG_PRINT("read_block",
("secondary request: new page in cache"));
}
@@ -1785,38 +2512,66 @@ static void read_block(KEY_CACHE *keycache,
have to be a multiple of key_cache_block_size;
*/
-byte *key_cache_read(KEY_CACHE *keycache,
+uchar *key_cache_read(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
- byte *buff, uint length,
+ uchar *buff, uint length,
uint block_length __attribute__((unused)),
int return_buffer __attribute__((unused)))
{
+ my_bool locked_and_incremented= FALSE;
int error=0;
- uint offset= 0;
- byte *start= buff;
+ uchar *start= buff;
DBUG_ENTER("key_cache_read");
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
(uint) file, (ulong) filepos, length));
- if (keycache->can_be_used)
+ if (keycache->key_cache_inited)
{
/* Key cache is used */
reg1 BLOCK_LINK *block;
uint read_length;
+ uint offset;
uint status;
int page_st;
+ /*
+ When the key cache is once initialized, we use the cache_lock to
+ reliably distinguish the cases of normal operation, resizing, and
+ disabled cache. We always increment and decrement
+ 'cnt_for_resize_op' so that a resizer can wait for pending I/O.
+ */
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /*
+ Cache resizing has two phases: Flushing and re-initializing. In
+ the flush phase read requests are allowed to bypass the cache for
+ blocks not in the cache. find_key_block() returns NULL in this
+ case.
+
+ After the flush phase new I/O requests must wait until the
+ re-initialization is done. The re-initialization can be done only
+ if no I/O request is in progress. The reason is that
+ key_cache_block_size can change. With enabled cache, I/O is done
+ in chunks of key_cache_block_size. Every chunk tries to use a
+ cache block first. If the block size changes in the middle, a
+ block could be missed and old data could be read.
+ */
+ while (keycache->in_resize && !keycache->resize_in_flush)
+ wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
+ /* Register the I/O for the next resize. */
+ inc_counter_for_resize_op(keycache);
+ locked_and_incremented= TRUE;
+ /* Requested data may not always be aligned to cache blocks. */
offset= (uint) (filepos % keycache->key_cache_block_size);
/* Read data in key_cache_block_size increments */
do
{
- keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /* Cache could be disabled in a later iteration. */
+
if (!keycache->can_be_used)
- {
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
goto no_key_cache;
- }
+ /* Start reading at the beginning of the cache block. */
filepos-= offset;
+ /* Do not read beyond the end of the cache block. */
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
@@ -1826,34 +2581,61 @@ byte *key_cache_read(KEY_CACHE *keycache,
return_buffer=0;
#endif
- inc_counter_for_resize_op(keycache);
+ /* Request the cache block that matches file/pos. */
keycache->global_cache_r_requests++;
block=find_key_block(keycache, file, filepos, level, 0, &page_st);
- if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
- {
- /* The requested page is to be read into the block buffer */
- read_block(keycache, block,
- keycache->key_cache_block_size, read_length+offset,
- (my_bool)(page_st == PAGE_TO_BE_READ));
- }
- else if (! (block->status & BLOCK_ERROR) &&
- block->length < read_length + offset)
+ if (!block)
{
/*
- Impossible if nothing goes wrong:
- this could only happen if we are using a file with
- small key blocks and are trying to read outside the file
+ This happens only for requests submitted during key cache
+ resize. The block is not in the cache and shall not go in.
+ Read directly from file.
*/
- my_errno= -1;
- block->status|= BLOCK_ERROR;
+ keycache->global_cache_read++;
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ error= (my_pread(file, (uchar*) buff, read_length,
+ filepos + offset, MYF(MY_NABP)) != 0);
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ goto next_block;
+ }
+ if (!(block->status & BLOCK_ERROR))
+ {
+ if (page_st != PAGE_READ)
+ {
+ /* The requested page is to be read into the block buffer */
+ read_block(keycache, block,
+ keycache->key_cache_block_size, read_length+offset,
+ (my_bool)(page_st == PAGE_TO_BE_READ));
+ /*
+ A secondary request must now have the block assigned to the
+ requested file block. It does not hurt to check it for
+ primary requests too.
+ */
+ DBUG_ASSERT(keycache->can_be_used);
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT(block->hash_link->diskpos == filepos);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ }
+ else if (block->length < read_length + offset)
+ {
+ /*
+ Impossible if nothing goes wrong:
+ this could only happen if we are using a file with
+ small key blocks and are trying to read outside the file
+ */
+ my_errno= -1;
+ block->status|= BLOCK_ERROR;
+ }
}
- if (! ((status= block->status) & BLOCK_ERROR))
+ /* block status may have added BLOCK_ERROR in the above 'if'. */
+ if (!((status= block->status) & BLOCK_ERROR))
{
#ifndef THREAD
if (! return_buffer)
#endif
{
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
#if !defined(SERIALIZED_READ_FROM_CACHE)
keycache_pthread_mutex_unlock(&keycache->cache_lock);
#endif
@@ -1866,45 +2648,59 @@ byte *key_cache_read(KEY_CACHE *keycache,
#if !defined(SERIALIZED_READ_FROM_CACHE)
keycache_pthread_mutex_lock(&keycache->cache_lock);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
#endif
}
}
remove_reader(block);
+
/*
- Link the block into the LRU chain
- if it's the last submitted request for the block
- */
+ Link the block into the LRU ring if it's the last submitted
+ request for the block. This enables eviction for the block.
+ */
unreg_request(keycache, block, 1);
- dec_counter_for_resize_op(keycache);
-
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
-
if (status & BLOCK_ERROR)
- DBUG_RETURN((byte *) 0);
+ {
+ error= 1;
+ break;
+ }
#ifndef THREAD
/* This is only true if we where able to read everything in one block */
if (return_buffer)
DBUG_RETURN(block->buffer);
#endif
+ next_block:
buff+= read_length;
filepos+= read_length+offset;
offset= 0;
} while ((length-= read_length));
- DBUG_RETURN(start);
+ goto end;
}
-no_key_cache: /* Key cache is not used */
+no_key_cache:
+ /* Key cache is not used */
- /* We can't use mutex here as the key cache may not be initialized */
keycache->global_cache_r_requests++;
keycache->global_cache_read++;
- if (my_pread(file, (byte*) buff, length, filepos+offset, MYF(MY_NABP)))
+
+ if (locked_and_incremented)
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ if (my_pread(file, (uchar*) buff, length, filepos, MYF(MY_NABP)))
error= 1;
- DBUG_RETURN(error ? (byte*) 0 : start);
+ if (locked_and_incremented)
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+
+end:
+ if (locked_and_incremented)
+ {
+ dec_counter_for_resize_op(keycache);
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ }
+ DBUG_RETURN(error ? (uchar*) 0 : start);
}
@@ -1930,92 +2726,214 @@ no_key_cache: /* Key cache is not used */
int key_cache_insert(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
- byte *buff, uint length)
+ uchar *buff, uint length)
{
+ int error= 0;
DBUG_ENTER("key_cache_insert");
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
(uint) file,(ulong) filepos, length));
- if (keycache->can_be_used)
+ if (keycache->key_cache_inited)
{
/* Key cache is used */
reg1 BLOCK_LINK *block;
uint read_length;
- int page_st;
- int error;
uint offset;
+ int page_st;
+ my_bool locked_and_incremented= FALSE;
+ /*
+ When the keycache is once initialized, we use the cache_lock to
+ reliably distinguish the cases of normal operation, resizing, and
+ disabled cache. We always increment and decrement
+ 'cnt_for_resize_op' so that a resizer can wait for pending I/O.
+ */
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /*
+ We do not load index data into a disabled cache nor into an
+ ongoing resize.
+ */
+ if (!keycache->can_be_used || keycache->in_resize)
+ goto no_key_cache;
+ /* Register the pseudo I/O for the next resize. */
+ inc_counter_for_resize_op(keycache);
+ locked_and_incremented= TRUE;
+ /* Loaded data may not always be aligned to cache blocks. */
offset= (uint) (filepos % keycache->key_cache_block_size);
+ /* Load data in key_cache_block_size increments. */
do
{
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- if (!keycache->can_be_used)
- {
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
- DBUG_RETURN(0);
- }
- /* Read data into key cache from buff in key_cache_block_size incr. */
+ /* Cache could be disabled or resizing in a later iteration. */
+ if (!keycache->can_be_used || keycache->in_resize)
+ goto no_key_cache;
+ /* Start loading at the beginning of the cache block. */
filepos-= offset;
+ /* Do not load beyond the end of the cache block. */
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
- inc_counter_for_resize_op(keycache);
+ /* The block has been read by the caller already. */
+ keycache->global_cache_read++;
+ /* Request the cache block that matches file/pos. */
keycache->global_cache_r_requests++;
block= find_key_block(keycache, file, filepos, level, 0, &page_st);
- if (block->status != BLOCK_ERROR && page_st != PAGE_READ)
+ if (!block)
{
- /* The requested page is to be read into the block buffer */
-#if !defined(SERIALIZED_READ_FROM_CACHE)
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
/*
- Here other threads may step in and register as secondary readers.
- They will register in block->wqueue[COND_FOR_REQUESTED].
+ This happens only for requests submitted during key cache
+ resize. The block is not in the cache and shall not go in.
+ Stop loading index data.
*/
+ goto no_key_cache;
+ }
+ if (!(block->status & BLOCK_ERROR))
+ {
+ if ((page_st == PAGE_WAIT_TO_BE_READ) ||
+ ((page_st == PAGE_TO_BE_READ) &&
+ (offset || (read_length < keycache->key_cache_block_size))))
+ {
+ /*
+ Either
+
+ this is a secondary request for a block to be read into the
+ cache. The block is in eviction. It is not yet assigned to
+ the requested file block (It does not point to the right
+ hash_link). So we cannot call remove_reader() on the block.
+ And we cannot access the hash_link directly here. We need to
+ wait until the assignment is complete. read_block() executes
+ the correct wait when called with primary == FALSE.
+
+ Or
+
+ this is a primary request for a block to be read into the
+ cache and the supplied data does not fill the whole block.
+
+ This function is called on behalf of a LOAD INDEX INTO CACHE
+ statement, which is a read-only task and allows other
+ readers. It is possible that a parallel running reader tries
+ to access this block. If it needs more data than has been
+ supplied here, it would report an error. To be sure that we
+ have all data in the block that is available in the file, we
+ read the block ourselves.
+
+ Though reading again what the caller did read already is an
+ expensive operation, we need to do this for correctness.
+ */
+ read_block(keycache, block, keycache->key_cache_block_size,
+ read_length + offset, (page_st == PAGE_TO_BE_READ));
+ /*
+ A secondary request must now have the block assigned to the
+ requested file block. It does not hurt to check it for
+ primary requests too.
+ */
+ DBUG_ASSERT(keycache->can_be_used);
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT(block->hash_link->diskpos == filepos);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ }
+ else if (page_st == PAGE_TO_BE_READ)
+ {
+ /*
+ This is a new block in the cache. If we come here, we have
+ data for the whole block.
+ */
+ DBUG_ASSERT(block->hash_link->requests);
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
+ (block->status & BLOCK_READ));
+
+#if !defined(SERIALIZED_READ_FROM_CACHE)
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ /*
+ Here other threads may step in and register as secondary readers.
+ They will register in block->wqueue[COND_FOR_REQUESTED].
+ */
#endif
- /* Copy data from buff */
- if (!(read_length & 511))
- bmove512(block->buffer+offset, buff, read_length);
- else
- memcpy(block->buffer+offset, buff, (size_t) read_length);
+ /* Copy data from buff */
+ if (!(read_length & 511))
+ bmove512(block->buffer+offset, buff, read_length);
+ else
+ memcpy(block->buffer+offset, buff, (size_t) read_length);
#if !defined(SERIALIZED_READ_FROM_CACHE)
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- /* Here we are alone again. */
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
+ (block->status & BLOCK_READ));
#endif
- block->status= BLOCK_READ;
- block->length= read_length+offset;
- KEYCACHE_DBUG_PRINT("key_cache_insert",
- ("primary request: new page in cache"));
- /* Signal that all pending requests for this now can be processed. */
- if (block->wqueue[COND_FOR_REQUESTED].last_thread)
- release_queue(&block->wqueue[COND_FOR_REQUESTED]);
- }
+ /*
+ After the data is in the buffer, we can declare the block
+ valid. Now other threads do not need to register as
+ secondary readers any more. They can immediately access the
+ block.
+ */
+ block->status|= BLOCK_READ;
+ block->length= read_length+offset;
+ /*
+ Do not set block->offset here. If this block is marked
+ BLOCK_CHANGED later, we want to flush only the modified part. So
+ only a writer may set block->offset down from
+ keycache->key_cache_block_size.
+ */
+ KEYCACHE_DBUG_PRINT("key_cache_insert",
+ ("primary request: new page in cache"));
+ /* Signal all pending requests. */
+ release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
+ }
+ else
+ {
+ /*
+ page_st == PAGE_READ. The block is in the buffer. All data
+ must already be present. Blocks are always read with all
+ data available on file. Assert that the block does not have
+ less contents than the preloader supplies. If the caller has
+ data beyond block->length, it means that a file write has
+ been done while this block was in cache and not extended
+ with the new data. If the condition is met, we can simply
+ ignore the block.
+ */
+ DBUG_ASSERT((page_st == PAGE_READ) &&
+ (read_length + offset <= block->length));
+ }
+
+ /*
+ A secondary request must now have the block assigned to the
+ requested file block. It does not hurt to check it for primary
+ requests too.
+ */
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT(block->hash_link->diskpos == filepos);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ } /* end of if (!(block->status & BLOCK_ERROR)) */
+
remove_reader(block);
+
/*
- Link the block into the LRU chain
- if it's the last submitted request for the block
+ Link the block into the LRU ring if it's the last submitted
+ request for the block. This enables eviction for the block.
*/
unreg_request(keycache, block, 1);
error= (block->status & BLOCK_ERROR);
- dec_counter_for_resize_op(keycache);
-
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
-
if (error)
- DBUG_RETURN(1);
+ break;
buff+= read_length;
filepos+= read_length+offset;
offset= 0;
} while ((length-= read_length));
+
+ no_key_cache:
+ if (locked_and_incremented)
+ dec_counter_for_resize_op(keycache);
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -2044,15 +2962,17 @@ int key_cache_insert(KEY_CACHE *keycache,
It ensures that this data is flushed to the file if dont_write is FALSE.
Filepos must be a multiple of 'block_length', but it doesn't
have to be a multiple of key_cache_block_size;
+
+ dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
*/
int key_cache_write(KEY_CACHE *keycache,
File file, my_off_t filepos, int level,
- byte *buff, uint length,
+ uchar *buff, uint length,
uint block_length __attribute__((unused)),
int dont_write)
{
- reg1 BLOCK_LINK *block;
+ my_bool locked_and_incremented= FALSE;
int error=0;
DBUG_ENTER("key_cache_write");
DBUG_PRINT("enter",
@@ -2062,10 +2982,14 @@ int key_cache_write(KEY_CACHE *keycache,
if (!dont_write)
{
- /* Force writing from buff into disk */
+ /* purecov: begin inspected */
+ /* Not used in the server. */
+ /* Force writing from buff into disk. */
+ keycache->global_cache_w_requests++;
keycache->global_cache_write++;
if (my_pwrite(file, buff, length, filepos, MYF(MY_NABP | MY_WAIT_IF_FULL)))
DBUG_RETURN(1);
+ /* purecov: end */
}
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
@@ -2073,92 +2997,222 @@ int key_cache_write(KEY_CACHE *keycache,
test_key_cache(keycache, "start of key_cache_write", 1););
#endif
- if (keycache->can_be_used)
+ if (keycache->key_cache_inited)
{
/* Key cache is used */
+ reg1 BLOCK_LINK *block;
uint read_length;
- int page_st;
uint offset;
+ int page_st;
+ /*
+ When the key cache is once initialized, we use the cache_lock to
+ reliably distinguish the cases of normal operation, resizing, and
+ disabled cache. We always increment and decrement
+ 'cnt_for_resize_op' so that a resizer can wait for pending I/O.
+ */
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /*
+ Cache resizing has two phases: Flushing and re-initializing. In
+ the flush phase write requests can modify dirty blocks that are
+ not yet in flush. Otherwise they are allowed to bypass the cache.
+ find_key_block() returns NULL in both cases (clean blocks and
+ non-cached blocks).
+
+ After the flush phase new I/O requests must wait until the
+ re-initialization is done. The re-initialization can be done only
+ if no I/O request is in progress. The reason is that
+ key_cache_block_size can change. With enabled cache I/O is done in
+ chunks of key_cache_block_size. Every chunk tries to use a cache
+ block first. If the block size changes in the middle, a block
+ could be missed and data could be written below a cached block.
+ */
+ while (keycache->in_resize && !keycache->resize_in_flush)
+ wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
+ /* Register the I/O for the next resize. */
+ inc_counter_for_resize_op(keycache);
+ locked_and_incremented= TRUE;
+ /* Requested data may not always be aligned to cache blocks. */
offset= (uint) (filepos % keycache->key_cache_block_size);
+ /* Write data in key_cache_block_size increments. */
do
{
- keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /* Cache could be disabled in a later iteration. */
if (!keycache->can_be_used)
- {
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
goto no_key_cache;
- }
- /* Write data in key_cache_block_size increments */
+ /* Start writing at the beginning of the cache block. */
filepos-= offset;
+ /* Do not write beyond the end of the cache block. */
read_length= length;
set_if_smaller(read_length, keycache->key_cache_block_size-offset);
KEYCACHE_DBUG_ASSERT(read_length > 0);
- inc_counter_for_resize_op(keycache);
+ /* Request the cache block that matches file/pos. */
keycache->global_cache_w_requests++;
block= find_key_block(keycache, file, filepos, level, 1, &page_st);
if (!block)
{
- /* It happens only for requests submitted during resize operation */
- dec_counter_for_resize_op(keycache);
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
- if (dont_write)
+ /*
+ This happens only for requests submitted during key cache
+ resize. The block is not in the cache and shall not go in.
+ Write directly to file.
+ */
+ if (dont_write)
{
- keycache->global_cache_w_requests++;
+ /* Used in the server. */
keycache->global_cache_write++;
- if (my_pwrite(file, (byte*) buff, length, filepos,
- MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ if (my_pwrite(file, (uchar*) buff, read_length, filepos + offset,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
error=1;
- }
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ }
goto next_block;
}
-
- if (block->status != BLOCK_ERROR && page_st != PAGE_READ &&
- (offset || read_length < keycache->key_cache_block_size))
+ /*
+ Prevent block from flushing and from being selected for to be
+ freed. This must be set when we release the cache_lock.
+ However, we must not set the status of the block before it is
+ assigned to this file/pos.
+ */
+ if (page_st != PAGE_WAIT_TO_BE_READ)
+ block->status|= BLOCK_FOR_UPDATE;
+ /*
+ We must read the file block first if it is not yet in the cache
+ and we do not replace all of its contents.
+
+ In cases where the cache block is big enough to contain (parts
+ of) index blocks of different indexes, our request can be
+ secondary (PAGE_WAIT_TO_BE_READ). In this case another thread is
+ reading the file block. If the read completes after us, it
+ overwrites our new contents with the old contents. So we have to
+ wait for the other thread to complete the read of this block.
+ read_block() takes care for the wait.
+ */
+ if (!(block->status & BLOCK_ERROR) &&
+ ((page_st == PAGE_TO_BE_READ &&
+ (offset || read_length < keycache->key_cache_block_size)) ||
+ (page_st == PAGE_WAIT_TO_BE_READ)))
+ {
read_block(keycache, block,
offset + read_length >= keycache->key_cache_block_size?
offset : keycache->key_cache_block_size,
- offset,(my_bool)(page_st == PAGE_TO_BE_READ));
+ offset, (page_st == PAGE_TO_BE_READ));
+ DBUG_ASSERT(keycache->can_be_used);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ /*
+ Prevent block from flushing and from being selected for to be
+ freed. This must be set when we release the cache_lock.
+ Here we set it in case we could not set it above.
+ */
+ block->status|= BLOCK_FOR_UPDATE;
+ }
+ /*
+ The block should always be assigned to the requested file block
+ here. It need not be BLOCK_READ when overwriting the whole block.
+ */
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT(block->hash_link->diskpos == filepos);
+ DBUG_ASSERT(block->status & BLOCK_IN_USE);
+ DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
+ /*
+ The block to be written must not be marked BLOCK_REASSIGNED.
+ Otherwise it could be freed in dirty state or reused without
+ another flush during eviction. It must also not be in flush.
+ Otherwise the old contens may have been flushed already and
+ the flusher could clear BLOCK_CHANGED without flushing the
+ new changes again.
+ */
+ DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
+
+ while (block->status & BLOCK_IN_FLUSHWRITE)
+ {
+ /*
+ Another thread is flushing the block. It was dirty already.
+ Wait until the block is flushed to file. Otherwise we could
+ modify the buffer contents just while it is written to file.
+ An unpredictable file block contents would be the result.
+ While we wait, several things can happen to the block,
+ including another flush. But the block cannot be reassigned to
+ another hash_link until we release our request on it.
+ */
+ wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
+ DBUG_ASSERT(keycache->can_be_used);
+ DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
+ /* Still must not be marked for free. */
+ DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
+ DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
+ }
+
+ /*
+ We could perhaps release the cache_lock during access of the
+ data like in the other functions. Locks outside of the key cache
+ assure that readers and a writer do not access the same range of
+ data. Parallel accesses should happen only if the cache block
+ contains multiple index block(fragment)s. So different parts of
+ the buffer would be read/written. An attempt to flush during
+ memcpy() is prevented with BLOCK_FOR_UPDATE.
+ */
+ if (!(block->status & BLOCK_ERROR))
+ {
+#if !defined(SERIALIZED_READ_FROM_CACHE)
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+#endif
+ if (!(read_length & 511))
+ bmove512(block->buffer+offset, buff, read_length);
+ else
+ memcpy(block->buffer+offset, buff, (size_t) read_length);
+
+#if !defined(SERIALIZED_READ_FROM_CACHE)
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+#endif
+ }
if (!dont_write)
{
- /* buff has been written to disk at start */
+ /* Not used in the server. buff has been written to disk at start. */
if ((block->status & BLOCK_CHANGED) &&
(!offset && read_length >= keycache->key_cache_block_size))
link_to_file_list(keycache, block, block->hash_link->file, 1);
}
else if (! (block->status & BLOCK_CHANGED))
link_to_changed_list(keycache, block);
+ block->status|=BLOCK_READ;
+ /*
+ Allow block to be selected for to be freed. Since it is marked
+ BLOCK_CHANGED too, it won't be selected for to be freed without
+ a flush.
+ */
+ block->status&= ~BLOCK_FOR_UPDATE;
set_if_smaller(block->offset, offset);
set_if_bigger(block->length, read_length+offset);
- if (! (block->status & BLOCK_ERROR))
- {
- if (!(read_length & 511))
- bmove512(block->buffer+offset, buff, read_length);
- else
- memcpy(block->buffer+offset, buff, (size_t) read_length);
- }
+ /* Threads may be waiting for the changes to be complete. */
+ release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
- block->status|=BLOCK_READ;
+ /*
+ If only a part of the cache block is to be replaced, and the
+ rest has been read from file, then the cache lock has been
+ released for I/O and it could be possible that another thread
+ wants to evict or free the block and waits for it to be
+ released. So we must not just decrement hash_link->requests, but
+ also wake a waiting thread.
+ */
+ remove_reader(block);
- /* Unregister the request */
- block->hash_link->requests--;
+ /*
+ Link the block into the LRU ring if it's the last submitted
+ request for the block. This enables eviction for the block.
+ */
unreg_request(keycache, block, 1);
if (block->status & BLOCK_ERROR)
{
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
error= 1;
break;
}
- dec_counter_for_resize_op(keycache);
-
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
-
next_block:
buff+= read_length;
filepos+= read_length+offset;
@@ -2172,14 +3226,24 @@ no_key_cache:
/* Key cache is not used */
if (dont_write)
{
+ /* Used in the server. */
keycache->global_cache_w_requests++;
keycache->global_cache_write++;
- if (my_pwrite(file, (byte*) buff, length, filepos,
+ if (locked_and_incremented)
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ if (my_pwrite(file, (uchar*) buff, length, filepos,
MYF(MY_NABP | MY_WAIT_IF_FULL)))
error=1;
+ if (locked_and_incremented)
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
}
end:
+ if (locked_and_incremented)
+ {
+ dec_counter_for_resize_op(keycache);
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ }
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("exec",
test_key_cache(keycache, "end of key_cache_write", 1););
@@ -2189,9 +3253,30 @@ end:
/*
- Free block: remove reference to it from hash table,
- remove it from the chain file of dirty/clean blocks
- and add it to the free list.
+ Free block.
+
+ SYNOPSIS
+ free_block()
+ keycache Pointer to a key cache data structure
+ block Pointer to the block to free
+
+ DESCRIPTION
+ Remove reference to block from hash table.
+ Remove block from the chain of clean blocks.
+ Add block to the free list.
+
+ NOTE
+ Block must not be free (status == 0).
+ Block must not be in free_block_list.
+ Block must not be in the LRU ring.
+ Block must not be in eviction (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH).
+ Block must not be in free (BLOCK_REASSIGNED).
+ Block must not be in flush (BLOCK_IN_FLUSH).
+ Block must not be dirty (BLOCK_CHANGED).
+ Block must not be in changed_blocks (dirty) hash.
+ Block must be in file_blocks (clean) hash.
+ Block must refer to a hash_link.
+ Block must have a request registered on it.
*/
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
@@ -2200,6 +3285,31 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
KEYCACHE_DBUG_PRINT("free_block",
("block %u to be freed, hash_link %p",
BLOCK_NUMBER(block), block->hash_link));
+ /*
+ Assert that the block is not free already. And that it is in a clean
+ state. Note that the block might just be assigned to a hash_link and
+ not yet read (BLOCK_READ may not be set here). In this case a reader
+ is registered in the hash_link and free_block() will wait for it
+ below.
+ */
+ DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
+ !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
+ BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
+ /* Assert that the block is in a file_blocks chain. */
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ /* Assert that the block is not in the LRU ring. */
+ DBUG_ASSERT(!block->next_used && !block->prev_used);
+ /*
+ IMHO the below condition (if()) makes no sense. I can't see how it
+ could be possible that free_block() is entered with a NULL hash_link
+ pointer. The only place where it can become NULL is in free_block()
+ (or before its first use ever, but for those blocks free_block() is
+ not called). I don't remove the conditional as it cannot harm, but
+ place an DBUG_ASSERT to confirm my hypothesis. Eventually the
+ condition (if()) can be removed.
+ */
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
if (block->hash_link)
{
/*
@@ -2210,24 +3320,77 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
*/
block->status|= BLOCK_REASSIGNED;
wait_for_readers(keycache, block);
- unlink_hash(keycache, block->hash_link);
+ /*
+ The block must not have been freed by another thread. Repeat some
+ checks. An additional requirement is that it must be read now
+ (BLOCK_READ).
+ */
+ DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
+ DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
+ BLOCK_REASSIGNED)) &&
+ !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_IN_FLUSH | BLOCK_CHANGED |
+ BLOCK_FOR_UPDATE)));
+ DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
+ DBUG_ASSERT(!block->prev_used);
+ /*
+ Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
+ thread (through unreg_request() below), other threads must not see
+ this flag. They could become confused.
+ */
+ block->status&= ~BLOCK_REASSIGNED;
+ /*
+ Do not release the hash_link until the block is off all lists.
+ At least not if we hand it over for eviction in unreg_request().
+ */
}
- unlink_changed(block);
- block->status= 0;
- block->length= 0;
- block->offset= keycache->key_cache_block_size;
- KEYCACHE_THREAD_TRACE("free block");
- KEYCACHE_DBUG_PRINT("free_block",
- ("block is freed"));
+ /*
+ Unregister the block request and link the block into the LRU ring.
+ This enables eviction for the block. If the LRU ring was empty and
+ threads are waiting for a block, then the block wil be handed over
+ for eviction immediately. Otherwise we will unlink it from the LRU
+ ring again, without releasing the lock in between. So decrementing
+ the request counter and updating statistics are the only relevant
+ operation in this case. Assert that there are no other requests
+ registered.
+ */
+ DBUG_ASSERT(block->requests == 1);
unreg_request(keycache, block, 0);
- block->hash_link= NULL;
+ /*
+ Note that even without releasing the cache lock it is possible that
+ the block is immediately selected for eviction by link_block() and
+ thus not added to the LRU ring. In this case we must not touch the
+ block any more.
+ */
+ if (block->status & BLOCK_IN_EVICTION)
+ return;
- /* Remove the free block from the LRU ring. */
+ /* Here the block must be in the LRU ring. Unlink it again. */
+ DBUG_ASSERT(block->next_used && block->prev_used &&
+ *block->prev_used == block);
unlink_block(keycache, block);
if (block->temperature == BLOCK_WARM)
keycache->warm_blocks--;
block->temperature= BLOCK_COLD;
+
+ /* Remove from file_blocks hash. */
+ unlink_changed(block);
+
+ /* Remove reference to block from hash table. */
+ unlink_hash(keycache, block->hash_link);
+ block->hash_link= NULL;
+
+ block->status= 0;
+ block->length= 0;
+ block->offset= keycache->key_cache_block_size;
+ KEYCACHE_THREAD_TRACE("free block");
+ KEYCACHE_DBUG_PRINT("free_block", ("block is freed"));
+
+ /* Enforced by unlink_changed(), but just to be sure. */
+ DBUG_ASSERT(!block->next_changed && !block->prev_changed);
+ /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
+ DBUG_ASSERT(!block->next_used && !block->prev_used);
/* Insert the free block in the free list. */
block->next_used= keycache->free_block_list;
keycache->free_block_list= block;
@@ -2235,8 +3398,7 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
keycache->blocks_unused++;
/* All pending requests for this page must be resubmitted. */
- if (block->wqueue[COND_FOR_SAVED].last_thread)
- release_queue(&block->wqueue[COND_FOR_SAVED]);
+ release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
}
@@ -2267,57 +3429,102 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
we are guarunteed no thread will change them
*/
- qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
+ qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
keycache_pthread_mutex_lock(&keycache->cache_lock);
+ /*
+ Note: Do not break the loop. We have registered a request on every
+ block in 'cache'. These must be unregistered by free_block() or
+ unreg_request().
+ */
for ( ; cache != end ; cache++)
{
BLOCK_LINK *block= *cache;
KEYCACHE_DBUG_PRINT("flush_cached_blocks",
("block %u to be flushed", BLOCK_NUMBER(block)));
- keycache_pthread_mutex_unlock(&keycache->cache_lock);
- error= my_pwrite(file,
- block->buffer+block->offset,
- block->length - block->offset,
- block->hash_link->diskpos+ block->offset,
- MYF(MY_NABP | MY_WAIT_IF_FULL));
- keycache_pthread_mutex_lock(&keycache->cache_lock);
- keycache->global_cache_write++;
- if (error)
+ /*
+ If the block contents is going to be changed, we abandon the flush
+ for this block. flush_key_blocks_int() will restart its search and
+ handle the block properly.
+ */
+ if (!(block->status & BLOCK_FOR_UPDATE))
{
- block->status|= BLOCK_ERROR;
- if (!last_errno)
- last_errno= errno ? errno : -1;
+ /* Blocks coming here must have a certain status. */
+ DBUG_ASSERT(block->hash_link);
+ DBUG_ASSERT(block->hash_link->block == block);
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
+ (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
+ block->status|= BLOCK_IN_FLUSHWRITE;
+ keycache_pthread_mutex_unlock(&keycache->cache_lock);
+ error= my_pwrite(file,
+ block->buffer+block->offset,
+ block->length - block->offset,
+ block->hash_link->diskpos+ block->offset,
+ MYF(MY_NABP | MY_WAIT_IF_FULL));
+ keycache_pthread_mutex_lock(&keycache->cache_lock);
+ keycache->global_cache_write++;
+ if (error)
+ {
+ block->status|= BLOCK_ERROR;
+ if (!last_errno)
+ last_errno= errno ? errno : -1;
+ }
+ block->status&= ~BLOCK_IN_FLUSHWRITE;
+ /* Block must not have changed status except BLOCK_FOR_UPDATE. */
+ DBUG_ASSERT(block->hash_link);
+ DBUG_ASSERT(block->hash_link->block == block);
+ DBUG_ASSERT(block->hash_link->file == file);
+ DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
+ (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
+ /*
+ Set correct status and link in right queue for free or later use.
+ free_block() must not see BLOCK_CHANGED and it may need to wait
+ for readers of the block. These should not see the block in the
+ wrong hash. If not freeing the block, we need to have it in the
+ right queue anyway.
+ */
+ link_to_file_list(keycache, block, file, 1);
+
}
+ block->status&= ~BLOCK_IN_FLUSH;
/*
Let to proceed for possible waiting requests to write to the block page.
It might happen only during an operation to resize the key cache.
*/
- if (block->wqueue[COND_FOR_SAVED].last_thread)
- release_queue(&block->wqueue[COND_FOR_SAVED]);
+ release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
/* type will never be FLUSH_IGNORE_CHANGED here */
- if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
+ if (!(type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE) &&
+ !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_FOR_UPDATE)))
{
- keycache->blocks_changed--;
- keycache->global_blocks_changed--;
+ /*
+ Note that a request has been registered against the block in
+ flush_key_blocks_int().
+ */
free_block(keycache, block);
}
else
{
- block->status&= ~BLOCK_IN_FLUSH;
- link_to_file_list(keycache, block, file, 1);
+ /*
+ Link the block into the LRU ring if it's the last submitted
+ request for the block. This enables eviction for the block.
+ Note that a request has been registered against the block in
+ flush_key_blocks_int().
+ */
unreg_request(keycache, block, 1);
}
- }
+ } /* end of for ( ; cache != end ; cache++) */
return last_errno;
}
/*
- flush all key blocks for a file to disk, but don't do any mutex locks
+ flush all key blocks for a file to disk, but don't do any mutex locks.
+ SYNOPSIS
flush_key_blocks_int()
keycache pointer to a key cache data structure
file handler for the file to flush to
@@ -2328,6 +3535,10 @@ static int flush_cached_blocks(KEY_CACHE *keycache,
from flush_key_blocks and flush_all_key_blocks (the later one does the
mutex lock in the resize_key_cache() function).
+ We do only care about changed blocks that exist when the function is
+ entered. We do not guarantee that all changed blocks of the file are
+ flushed if more blocks change while this function is running.
+
RETURN
0 ok
1 error
@@ -2338,6 +3549,7 @@ static int flush_key_blocks_int(KEY_CACHE *keycache,
{
BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
int last_errno= 0;
+ int last_errcnt= 0;
DBUG_ENTER("flush_key_blocks_int");
DBUG_PRINT("enter",("file: %d blocks_used: %lu blocks_changed: %lu",
file, keycache->blocks_used, keycache->blocks_changed));
@@ -2353,9 +3565,11 @@ static int flush_key_blocks_int(KEY_CACHE *keycache,
{
/* Key cache exists and flush is not disabled */
int error= 0;
- uint count= 0;
+ uint count= FLUSH_CACHE;
BLOCK_LINK **pos,**end;
BLOCK_LINK *first_in_switch= NULL;
+ BLOCK_LINK *last_in_flush;
+ BLOCK_LINK *last_for_update;
BLOCK_LINK *block, *next;
#if defined(KEYCACHE_DEBUG)
uint cnt=0;
@@ -2367,28 +3581,39 @@ static int flush_key_blocks_int(KEY_CACHE *keycache,
Count how many key blocks we have to cache to be able
to flush all dirty pages with minimum seek moves
*/
+ count= 0;
for (block= keycache->changed_blocks[FILE_HASH(file)] ;
block ;
block= block->next_changed)
{
- if (block->hash_link->file == file)
+ if ((block->hash_link->file == file) &&
+ !(block->status & BLOCK_IN_FLUSH))
{
count++;
KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
}
}
- /* Allocate a new buffer only if its bigger than the one we have */
- if (count > FLUSH_CACHE &&
+ /*
+ Allocate a new buffer only if its bigger than the one we have.
+ Assure that we always have some entries for the case that new
+ changed blocks appear while we need to wait for something.
+ */
+ if ((count > FLUSH_CACHE) &&
!(cache= (BLOCK_LINK**) my_malloc(sizeof(BLOCK_LINK*)*count,
MYF(0))))
- {
cache= cache_buff;
+ /*
+ After a restart there could be more changed blocks than now.
+ So we should not let count become smaller than the fixed buffer.
+ */
+ if (cache == cache_buff)
count= FLUSH_CACHE;
- }
}
/* Retrieve the blocks and write them to a buffer to be flushed */
restart:
+ last_in_flush= NULL;
+ last_for_update= NULL;
end= (pos= cache)+count;
for (block= keycache->changed_blocks[FILE_HASH(file)] ;
block ;
@@ -2401,123 +3626,353 @@ restart:
next= block->next_changed;
if (block->hash_link->file == file)
{
- /*
- Mark the block with BLOCK_IN_FLUSH in order not to let
- other threads to use it for new pages and interfere with
- our sequence ot flushing dirty file pages
- */
- block->status|= BLOCK_IN_FLUSH;
-
- if (! (block->status & BLOCK_IN_SWITCH))
+ if (!(block->status & (BLOCK_IN_FLUSH | BLOCK_FOR_UPDATE)))
{
- /*
- We care only for the blocks for which flushing was not
- initiated by other threads as a result of page swapping
+ /*
+ Note: The special handling of BLOCK_IN_SWITCH is obsolete
+ since we set BLOCK_IN_FLUSH if the eviction includes a
+ flush. It can be removed in a later version.
*/
- reg_requests(keycache, block, 1);
- if (type != FLUSH_IGNORE_CHANGED)
+ if (!(block->status & BLOCK_IN_SWITCH))
{
- /* It's not a temporary file */
- if (pos == end)
+ /*
+ We care only for the blocks for which flushing was not
+ initiated by another thread and which are not in eviction.
+ Registering a request on the block unlinks it from the LRU
+ ring and protects against eviction.
+ */
+ reg_requests(keycache, block, 1);
+ if (type != FLUSH_IGNORE_CHANGED)
{
- /*
- This happens only if there is not enough
- memory for the big block
+ /* It's not a temporary file */
+ if (pos == end)
+ {
+ /*
+ This should happen relatively seldom. Remove the
+ request because we won't do anything with the block
+ but restart and pick it again in the next iteration.
+ */
+ unreg_request(keycache, block, 0);
+ /*
+ This happens only if there is not enough
+ memory for the big block
+ */
+ if ((error= flush_cached_blocks(keycache, file, cache,
+ end,type)))
+ {
+ /* Do not loop infinitely trying to flush in vain. */
+ if ((last_errno == error) && (++last_errcnt > 5))
+ goto err;
+ last_errno= error;
+ }
+ /*
+ Restart the scan as some other thread might have changed
+ the changed blocks chain: the blocks that were in switch
+ state before the flush started have to be excluded
+ */
+ goto restart;
+ }
+ /*
+ Mark the block with BLOCK_IN_FLUSH in order not to let
+ other threads to use it for new pages and interfere with
+ our sequence of flushing dirty file pages. We must not
+ set this flag before actually putting the block on the
+ write burst array called 'cache'.
*/
- if ((error= flush_cached_blocks(keycache, file, cache,
- end,type)))
- last_errno=error;
+ block->status|= BLOCK_IN_FLUSH;
+ /* Add block to the array for a write burst. */
+ *pos++= block;
+ }
+ else
+ {
+ /* It's a temporary file */
+ DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
+
/*
- Restart the scan as some other thread might have changed
- the changed blocks chain: the blocks that were in switch
- state before the flush started have to be excluded
+ free_block() must not be called with BLOCK_CHANGED. Note
+ that we must not change the BLOCK_CHANGED flag outside of
+ link_to_file_list() so that it is always in the correct
+ queue and the *blocks_changed counters are correct.
*/
- goto restart;
+ link_to_file_list(keycache, block, file, 1);
+ if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)))
+ {
+ /* A request has been registered against the block above. */
+ free_block(keycache, block);
+ }
+ else
+ {
+ /*
+ Link the block into the LRU ring if it's the last
+ submitted request for the block. This enables eviction
+ for the block. A request has been registered against
+ the block above.
+ */
+ unreg_request(keycache, block, 1);
+ }
}
- *pos++= block;
}
else
{
- /* It's a temporary file */
- keycache->blocks_changed--;
- keycache->global_blocks_changed--;
- free_block(keycache, block);
+ /*
+ Link the block into a list of blocks 'in switch'.
+
+ WARNING: Here we introduce a place where a changed block
+ is not in the changed_blocks hash! This is acceptable for
+ a BLOCK_IN_SWITCH. Never try this for another situation.
+ Other parts of the key cache code rely on changed blocks
+ being in the changed_blocks hash.
+ */
+ unlink_changed(block);
+ link_changed(block, &first_in_switch);
}
}
- else
+ else if (type != FLUSH_KEEP)
{
- /* Link the block into a list of blocks 'in switch' */
- unlink_changed(block);
- link_changed(block, &first_in_switch);
+ /*
+ During the normal flush at end of statement (FLUSH_KEEP) we
+ do not need to ensure that blocks in flush or update by
+ other threads are flushed. They will be flushed by them
+ later. In all other cases we must assure that we do not have
+ any changed block of this file in the cache when this
+ function returns.
+ */
+ if (block->status & BLOCK_IN_FLUSH)
+ {
+ /* Remember the last block found to be in flush. */
+ last_in_flush= block;
+ }
+ else
+ {
+ /* Remember the last block found to be selected for update. */
+ last_for_update= block;
+ }
}
}
}
if (pos != cache)
{
if ((error= flush_cached_blocks(keycache, file, cache, pos, type)))
+ {
+ /* Do not loop inifnitely trying to flush in vain. */
+ if ((last_errno == error) && (++last_errcnt > 5))
+ goto err;
last_errno= error;
+ }
+ /*
+ Do not restart here during the normal flush at end of statement
+ (FLUSH_KEEP). We have now flushed at least all blocks that were
+ changed when entering this function. In all other cases we must
+ assure that we do not have any changed block of this file in the
+ cache when this function returns.
+ */
+ if (type != FLUSH_KEEP)
+ goto restart;
}
- /* Wait until list of blocks in switch is empty */
+ if (last_in_flush)
+ {
+ /*
+ There are no blocks to be flushed by this thread, but blocks in
+ flush by other threads. Wait until one of the blocks is flushed.
+ Re-check the condition for last_in_flush. We may have unlocked
+ the cache_lock in flush_cached_blocks(). The state of the block
+ could have changed.
+ */
+ if (last_in_flush->status & BLOCK_IN_FLUSH)
+ wait_on_queue(&last_in_flush->wqueue[COND_FOR_SAVED],
+ &keycache->cache_lock);
+ /* Be sure not to lose a block. They may be flushed in random order. */
+ goto restart;
+ }
+ if (last_for_update)
+ {
+ /*
+ There are no blocks to be flushed by this thread, but blocks for
+ update by other threads. Wait until one of the blocks is updated.
+ Re-check the condition for last_for_update. We may have unlocked
+ the cache_lock in flush_cached_blocks(). The state of the block
+ could have changed.
+ */
+ if (last_for_update->status & BLOCK_FOR_UPDATE)
+ wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
+ &keycache->cache_lock);
+ /* The block is now changed. Flush it. */
+ goto restart;
+ }
+
+ /*
+ Wait until the list of blocks in switch is empty. The threads that
+ are switching these blocks will relink them to clean file chains
+ while we wait and thus empty the 'first_in_switch' chain.
+ */
while (first_in_switch)
{
#if defined(KEYCACHE_DEBUG)
cnt= 0;
#endif
- block= first_in_switch;
- {
-#ifdef THREAD
- struct st_my_thread_var *thread= my_thread_var;
- add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
- do
- {
- KEYCACHE_DBUG_PRINT("flush_key_blocks_int: wait",
- ("suspend thread %ld", thread->id));
- keycache_pthread_cond_wait(&thread->suspend,
- &keycache->cache_lock);
- }
- while (thread->next);
-#else
- KEYCACHE_DBUG_ASSERT(0);
- /* No parallel requests in single-threaded case */
-#endif
- }
+ wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
+ &keycache->cache_lock);
#if defined(KEYCACHE_DEBUG)
cnt++;
KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
#endif
+ /*
+ Do not restart here. We have flushed all blocks that were
+ changed when entering this function and were not marked for
+ eviction. Other threads have now flushed all remaining blocks in
+ the course of their eviction.
+ */
}
- /* The following happens very seldom */
+
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{
-#if defined(KEYCACHE_DEBUG)
- cnt=0;
-#endif
- for (block= keycache->file_blocks[FILE_HASH(file)] ;
- block ;
- block= next)
+ BLOCK_LINK *last_for_update= NULL;
+ BLOCK_LINK *last_in_switch= NULL;
+ uint total_found= 0;
+ uint found;
+
+ /*
+ Finally free all clean blocks for this file.
+ During resize this may be run by two threads in parallel.
+ */
+ do
{
-#if defined(KEYCACHE_DEBUG)
- cnt++;
- KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
-#endif
- next= block->next_changed;
- if (block->hash_link->file == file &&
- (! (block->status & BLOCK_CHANGED)
- || type == FLUSH_IGNORE_CHANGED))
+ found= 0;
+ for (block= keycache->file_blocks[FILE_HASH(file)] ;
+ block ;
+ block= next)
{
- reg_requests(keycache, block, 1);
- free_block(keycache, block);
- }
+ /* Remember the next block. After freeing we cannot get at it. */
+ next= block->next_changed;
+
+ /* Changed blocks cannot appear in the file_blocks hash. */
+ DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
+ if (block->hash_link->file == file)
+ {
+ /* We must skip blocks that will be changed. */
+ if (block->status & BLOCK_FOR_UPDATE)
+ {
+ last_for_update= block;
+ continue;
+ }
+
+ /*
+ We must not free blocks in eviction (BLOCK_IN_EVICTION |
+ BLOCK_IN_SWITCH) or blocks intended to be freed
+ (BLOCK_REASSIGNED).
+ */
+ if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
+ BLOCK_REASSIGNED)))
+ {
+ struct st_hash_link *next_hash_link;
+ my_off_t next_diskpos;
+ File next_file;
+ uint next_status;
+ uint hash_requests;
+
+ total_found++;
+ found++;
+ KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
+
+ /*
+ Register a request. This unlinks the block from the LRU
+ ring and protects it against eviction. This is required
+ by free_block().
+ */
+ reg_requests(keycache, block, 1);
+
+ /*
+ free_block() may need to wait for readers of the block.
+ This is the moment where the other thread can move the
+ 'next' block from the chain. free_block() needs to wait
+ if there are requests for the block pending.
+ */
+ if (next && (hash_requests= block->hash_link->requests))
+ {
+ /* Copy values from the 'next' block and its hash_link. */
+ next_status= next->status;
+ next_hash_link= next->hash_link;
+ next_diskpos= next_hash_link->diskpos;
+ next_file= next_hash_link->file;
+ DBUG_ASSERT(next == next_hash_link->block);
+ }
+
+ free_block(keycache, block);
+ /*
+ If we had to wait and the state of the 'next' block
+ changed, break the inner loop. 'next' may no longer be
+ part of the current chain.
+
+ We do not want to break the loop after every free_block(),
+ not even only after waits. The chain might be quite long
+ and contain blocks for many files. Traversing it again and
+ again to find more blocks for this file could become quite
+ inefficient.
+ */
+ if (next && hash_requests &&
+ ((next_status != next->status) ||
+ (next_hash_link != next->hash_link) ||
+ (next_file != next_hash_link->file) ||
+ (next_diskpos != next_hash_link->diskpos) ||
+ (next != next_hash_link->block)))
+ break;
+ }
+ else
+ {
+ last_in_switch= block;
+ }
+ }
+ } /* end for block in file_blocks */
+ } while (found);
+
+ /*
+ If any clean block has been found, we may have waited for it to
+ become free. In this case it could be possible that another clean
+ block became dirty. This is possible if the write request existed
+ before the flush started (BLOCK_FOR_UPDATE). Re-check the hashes.
+ */
+ if (total_found)
+ goto restart;
+
+ /*
+ To avoid an infinite loop, wait until one of the blocks marked
+ for update is updated.
+ */
+ if (last_for_update)
+ {
+ /* We did not wait. Block must not have changed status. */
+ DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
+ wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
+ &keycache->cache_lock);
+ goto restart;
}
- }
- }
+
+ /*
+ To avoid an infinite loop wait until one of the blocks marked
+ for eviction is switched.
+ */
+ if (last_in_switch)
+ {
+ /* We did not wait. Block must not have changed status. */
+ DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
+ BLOCK_IN_SWITCH |
+ BLOCK_REASSIGNED));
+ wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
+ &keycache->cache_lock);
+ goto restart;
+ }
+
+ } /* if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE)) */
+
+ } /* if (keycache->disk_blocks > 0 */
#ifndef DBUG_OFF
DBUG_EXECUTE("check_keycache",
test_key_cache(keycache, "end of flush_key_blocks", 0););
#endif
+err:
if (cache != cache_buff)
- my_free((gptr) cache, MYF(0));
+ my_free((uchar*) cache, MYF(0));
if (last_errno)
errno=last_errno; /* Return first error */
DBUG_RETURN(last_errno != 0);
@@ -2542,51 +3997,157 @@ restart:
int flush_key_blocks(KEY_CACHE *keycache,
File file, enum flush_type type)
{
- int res;
+ int res= 0;
DBUG_ENTER("flush_key_blocks");
DBUG_PRINT("enter", ("keycache: 0x%lx", (long) keycache));
- if (keycache->disk_blocks <= 0)
+ if (!keycache->key_cache_inited)
DBUG_RETURN(0);
+
keycache_pthread_mutex_lock(&keycache->cache_lock);
- inc_counter_for_resize_op(keycache);
- res= flush_key_blocks_int(keycache, file, type);
- dec_counter_for_resize_op(keycache);
+ /* While waiting for lock, keycache could have been ended. */
+ if (keycache->disk_blocks > 0)
+ {
+ inc_counter_for_resize_op(keycache);
+ res= flush_key_blocks_int(keycache, file, type);
+ dec_counter_for_resize_op(keycache);
+ }
keycache_pthread_mutex_unlock(&keycache->cache_lock);
DBUG_RETURN(res);
}
/*
- Flush all blocks in the key cache to disk
+ Flush all blocks in the key cache to disk.
+
+ SYNOPSIS
+ flush_all_key_blocks()
+ keycache pointer to key cache root structure
+
+ DESCRIPTION
+
+ Flushing of the whole key cache is done in two phases.
+
+ 1. Flush all changed blocks, waiting for them if necessary. Loop
+ until there is no changed block left in the cache.
+
+ 2. Free all clean blocks. Normally this means free all blocks. The
+ changed blocks were flushed in phase 1 and became clean. However we
+ may need to wait for blocks that are read by other threads. While we
+ wait, a clean block could become changed if that operation started
+ before the resize operation started. To be safe we must restart at
+ phase 1.
+
+ When we can run through the changed_blocks and file_blocks hashes
+ without finding a block any more, then we are done.
+
+ Note that we hold keycache->cache_lock all the time unless we need
+ to wait for something.
+
+ RETURN
+ 0 OK
+ != 0 Error
*/
static int flush_all_key_blocks(KEY_CACHE *keycache)
{
-#if defined(KEYCACHE_DEBUG)
- uint cnt=0;
-#endif
- while (keycache->blocks_changed > 0)
+ BLOCK_LINK *block;
+ uint total_found;
+ uint found;
+ uint idx;
+ DBUG_ENTER("flush_all_key_blocks");
+
+ do
{
- BLOCK_LINK *block;
- for (block= keycache->used_last->next_used ; ; block=block->next_used)
+ safe_mutex_assert_owner(&keycache->cache_lock);
+ total_found= 0;
+
+ /*
+ Phase1: Flush all changed blocks, waiting for them if necessary.
+ Loop until there is no changed block left in the cache.
+ */
+ do
{
- if (block->hash_link)
+ found= 0;
+ /* Step over the whole changed_blocks hash array. */
+ for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
{
-#if defined(KEYCACHE_DEBUG)
- cnt++;
- KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
-#endif
- if (flush_key_blocks_int(keycache, block->hash_link->file,
- FLUSH_RELEASE))
- return 1;
- break;
+ /*
+ If an array element is non-empty, use the first block from its
+ chain to find a file for flush. All changed blocks for this
+ file are flushed. So the same block will not appear at this
+ place again with the next iteration. New writes for blocks are
+ not accepted during the flush. If multiple files share the
+ same hash bucket, one of them will be flushed per iteration
+ of the outer loop of phase 1.
+ */
+ if ((block= keycache->changed_blocks[idx]))
+ {
+ found++;
+ /*
+ Flush dirty blocks but do not free them yet. They can be used
+ for reading until all other blocks are flushed too.
+ */
+ if (flush_key_blocks_int(keycache, block->hash_link->file,
+ FLUSH_FORCE_WRITE))
+ DBUG_RETURN(1);
+ }
}
- if (block == keycache->used_last)
- break;
- }
+
+ } while (found);
+
+ /*
+ Phase 2: Free all clean blocks. Normally this means free all
+ blocks. The changed blocks were flushed in phase 1 and became
+ clean. However we may need to wait for blocks that are read by
+ other threads. While we wait, a clean block could become changed
+ if that operation started before the resize operation started. To
+ be safe we must restart at phase 1.
+ */
+ do
+ {
+ found= 0;
+ /* Step over the whole file_blocks hash array. */
+ for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
+ {
+ /*
+ If an array element is non-empty, use the first block from its
+ chain to find a file for flush. All blocks for this file are
+ freed. So the same block will not appear at this place again
+ with the next iteration. If multiple files share the
+ same hash bucket, one of them will be flushed per iteration
+ of the outer loop of phase 2.
+ */
+ if ((block= keycache->file_blocks[idx]))
+ {
+ total_found++;
+ found++;
+ if (flush_key_blocks_int(keycache, block->hash_link->file,
+ FLUSH_RELEASE))
+ DBUG_RETURN(1);
+ }
+ }
+
+ } while (found);
+
+ /*
+ If any clean block has been found, we may have waited for it to
+ become free. In this case it could be possible that another clean
+ block became dirty. This is possible if the write request existed
+ before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
+ */
+ } while (total_found);
+
+#ifndef DBUG_OFF
+ /* Now there should not exist any block any more. */
+ for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
+ {
+ DBUG_ASSERT(!keycache->changed_blocks[idx]);
+ DBUG_ASSERT(!keycache->file_blocks[idx]);
}
- return 0;
+#endif
+
+ DBUG_RETURN(0);
}
@@ -2855,3 +4416,70 @@ void keycache_debug_log_close(void)
#endif /* defined(KEYCACHE_DEBUG_LOG) */
#endif /* defined(KEYCACHE_DEBUG) */
+
+#if !defined(DBUG_OFF)
+#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
+
+static int fail_block(BLOCK_LINK *block)
+{
+ F_B_PRT("block->next_used: %lx\n", (ulong) block->next_used);
+ F_B_PRT("block->prev_used: %lx\n", (ulong) block->prev_used);
+ F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
+ F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
+ F_B_PRT("block->hash_link: %lx\n", (ulong) block->hash_link);
+ F_B_PRT("block->status: %u\n", block->status);
+ F_B_PRT("block->length: %u\n", block->length);
+ F_B_PRT("block->offset: %u\n", block->offset);
+ F_B_PRT("block->requests: %u\n", block->requests);
+ F_B_PRT("block->temperature: %u\n", block->temperature);
+ return 0; /* Let the assert fail. */
+}
+
+static int fail_hlink(HASH_LINK *hlink)
+{
+ F_B_PRT("hlink->next: %lx\n", (ulong) hlink->next);
+ F_B_PRT("hlink->prev: %lx\n", (ulong) hlink->prev);
+ F_B_PRT("hlink->block: %lx\n", (ulong) hlink->block);
+ F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
+ F_B_PRT("hlink->file: %d\n", hlink->file);
+ return 0; /* Let the assert fail. */
+}
+
+static int cache_empty(KEY_CACHE *keycache)
+{
+ int errcnt= 0;
+ int idx;
+ if (keycache->disk_blocks <= 0)
+ return 1;
+ for (idx= 0; idx < keycache->disk_blocks; idx++)
+ {
+ BLOCK_LINK *block= keycache->block_root + idx;
+ if (block->status || block->requests || block->hash_link)
+ {
+ fprintf(stderr, "block index: %u\n", idx);
+ fail_block(block);
+ errcnt++;
+ }
+ }
+ for (idx= 0; idx < keycache->hash_links; idx++)
+ {
+ HASH_LINK *hash_link= keycache->hash_link_root + idx;
+ if (hash_link->requests || hash_link->block)
+ {
+ fprintf(stderr, "hash_link index: %u\n", idx);
+ fail_hlink(hash_link);
+ errcnt++;
+ }
+ }
+ if (errcnt)
+ {
+ fprintf(stderr, "blocks: %d used: %lu\n",
+ keycache->disk_blocks, keycache->blocks_used);
+ fprintf(stderr, "hash_links: %d used: %d\n",
+ keycache->hash_links, keycache->hash_links_used);
+ fprintf(stderr, "\n");
+ }
+ return !errcnt;
+}
+#endif
+
diff --git a/mysys/mf_keycaches.c b/mysys/mf_keycaches.c
index 51ad54159e5..6227a05ce06 100644
--- a/mysys/mf_keycaches.c
+++ b/mysys/mf_keycaches.c
@@ -44,9 +44,9 @@
typedef struct st_safe_hash_entry
{
- byte *key;
+ uchar *key;
uint length;
- byte *data;
+ uchar *data;
struct st_safe_hash_entry *next, **prev;
} SAFE_HASH_ENTRY;
@@ -57,7 +57,7 @@ typedef struct st_safe_hash_with_default
rw_lock_t mutex;
#endif
HASH hash;
- byte *default_value;
+ uchar *default_value;
SAFE_HASH_ENTRY *root;
} SAFE_HASH;
@@ -71,18 +71,18 @@ typedef struct st_safe_hash_with_default
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
{
DBUG_ENTER("free_assign_entry");
- my_free((gptr) entry, MYF(0));
+ my_free((uchar*) entry, MYF(0));
DBUG_VOID_RETURN;
}
/* Get key and length for a SAFE_HASH_ENTRY */
-static byte *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length=entry->length;
- return (byte*) entry->key;
+ return (uchar*) entry->key;
}
@@ -105,7 +105,7 @@ static byte *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, uint *length,
*/
static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
- byte *default_value)
+ uchar *default_value)
{
DBUG_ENTER("safe_hash");
if (hash_init(&hash->hash, &my_charset_bin, elements,
@@ -147,9 +147,9 @@ static void safe_hash_free(SAFE_HASH *hash)
Return the value stored for a key or default value if no key
*/
-static byte *safe_hash_search(SAFE_HASH *hash, const byte *key, uint length)
+static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
{
- byte *result;
+ uchar *result;
DBUG_ENTER("safe_hash_search");
rw_rdlock(&hash->mutex);
result= hash_search(&hash->hash, key, length);
@@ -183,8 +183,8 @@ static byte *safe_hash_search(SAFE_HASH *hash, const byte *key, uint length)
1 error (Can only be EOM). In this case my_message() is called.
*/
-static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
- byte *data)
+static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
+ uchar *data)
{
SAFE_HASH_ENTRY *entry;
my_bool error= 0;
@@ -206,7 +206,7 @@ static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
/* unlink entry from list */
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
- hash_delete(&hash->hash, (byte*) entry);
+ hash_delete(&hash->hash, (uchar*) entry);
goto end;
}
if (entry)
@@ -222,7 +222,7 @@ static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
error= 1;
goto end;
}
- entry->key= (byte*) (entry +1);
+ entry->key= (uchar*) (entry +1);
memcpy((char*) entry->key, (char*) key, length);
entry->length= length;
entry->data= data;
@@ -231,7 +231,7 @@ static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
entry->next->prev= &entry->next;
entry->prev= &hash->root;
hash->root= entry;
- if (my_hash_insert(&hash->hash, (byte*) entry))
+ if (my_hash_insert(&hash->hash, (uchar*) entry))
{
/* This can only happen if hash got out of memory */
my_free((char*) entry, MYF(0));
@@ -261,7 +261,7 @@ end:
default value.
*/
-static void safe_hash_change(SAFE_HASH *hash, byte *old_data, byte *new_data)
+static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
{
SAFE_HASH_ENTRY *entry, *next;
DBUG_ENTER("safe_hash_set");
@@ -277,7 +277,7 @@ static void safe_hash_change(SAFE_HASH *hash, byte *old_data, byte *new_data)
{
if ((*entry->prev= entry->next))
entry->next->prev= entry->prev;
- hash_delete(&hash->hash, (byte*) entry);
+ hash_delete(&hash->hash, (uchar*) entry);
}
else
entry->data= new_data;
@@ -299,7 +299,7 @@ static SAFE_HASH key_cache_hash;
my_bool multi_keycache_init(void)
{
- return safe_hash_init(&key_cache_hash, 16, (byte*) dflt_key_cache);
+ return safe_hash_init(&key_cache_hash, 16, (uchar*) dflt_key_cache);
}
@@ -325,7 +325,7 @@ void multi_keycache_free(void)
key cache to use
*/
-KEY_CACHE *multi_key_cache_search(byte *key, uint length)
+KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
{
if (!key_cache_hash.hash.records)
return dflt_key_cache;
@@ -349,15 +349,15 @@ KEY_CACHE *multi_key_cache_search(byte *key, uint length)
*/
-my_bool multi_key_cache_set(const byte *key, uint length,
+my_bool multi_key_cache_set(const uchar *key, uint length,
KEY_CACHE *key_cache)
{
- return safe_hash_set(&key_cache_hash, key, length, (byte*) 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, (byte*) old_data, (byte*) new_data);
+ safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
}
diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c
index ffa83cb20ec..48a69207839 100644
--- a/mysys/mf_loadpath.c
+++ b/mysys/mf_loadpath.c
@@ -23,7 +23,7 @@
/* if there is no path, prepend with own_path_prefix if given */
/* else unpack path according to current dir */
-my_string my_load_path(my_string to, const char *path,
+char * my_load_path(char * to, const char *path,
const char *own_path_prefix)
{
char buff[FN_REFLEN];
@@ -36,7 +36,7 @@ my_string my_load_path(my_string to, const char *path,
test_if_hard_path(path))
VOID(strmov(buff,path));
else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) ||
- (is_prefix((gptr) path,FN_PARENTDIR)) ||
+ (is_prefix(path,FN_PARENTDIR)) ||
! own_path_prefix)
{
if (is_cur)
diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c
index d14c24f35d7..a31b9595c85 100644
--- a/mysys/mf_pack.c
+++ b/mysys/mf_pack.c
@@ -24,17 +24,17 @@
#include <descrip.h>
#endif /* VMS */
-static my_string NEAR_F expand_tilde(my_string *path);
+static char * NEAR_F expand_tilde(char * *path);
/* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
/* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
/* to may be == from */
-void pack_dirname(my_string to, const char *from)
+void pack_dirname(char * to, const char *from)
{
int cwd_err;
- uint d_length,length,buff_length;
- my_string start;
+ size_t d_length,length,buff_length;
+ char * start;
char buff[FN_REFLEN];
DBUG_ENTER("pack_dirname");
@@ -50,13 +50,13 @@ void pack_dirname(my_string to, const char *from)
if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
{
- buff_length= (uint) strlen(buff);
- d_length=(uint) (start-to);
+ buff_length= strlen(buff);
+ d_length= (size_t) (start-to);
if ((start == to ||
(buff_length == d_length && !bcmp(buff,start,d_length))) &&
*start != FN_LIBCHAR && *start)
{ /* Put current dir before */
- bchange(to,d_length,buff,buff_length,(uint) strlen(to)+1);
+ bchange((uchar*) to, d_length, (uchar*) buff, buff_length, strlen(to)+1);
}
}
@@ -65,7 +65,7 @@ void pack_dirname(my_string to, const char *from)
length=0;
if (home_dir)
{
- length= (uint) strlen(home_dir);
+ length= strlen(home_dir);
if (home_dir[length-1] == FN_LIBCHAR)
length--; /* Don't test last '/' */
}
@@ -89,7 +89,7 @@ void pack_dirname(my_string to, const char *from)
}
if (is_prefix(to,buff))
{
- length= (uint) strlen(buff);
+ length= strlen(buff);
if (to[length])
(void) strmov_overlapp(to,to+length); /* Remove everything before */
else
@@ -106,21 +106,32 @@ void pack_dirname(my_string to, const char *from)
} /* pack_dirname */
- /* remove unwanted chars from dirname */
- /* if "/../" removes prev dir; "/~/" removes all before ~ */
- /* "//" is same as "/", except on Win32 at start of a file */
- /* "/./" is removed */
- /* Unpacks home_dir if "~/.." used */
- /* Unpacks current dir if if "./.." used */
+/*
+ remove unwanted chars from dirname
+
+ SYNOPSIS
+ cleanup_dirname()
+ to Store result here
+ from Dirname to fix. May be same as to
+
+ IMPLEMENTATION
+ "/../" removes prev dir
+ "/~/" removes all before ~
+ //" is same as "/", except on Win32 at start of a file
+ "/./" is removed
+ Unpacks home_dir if "~/.." used
+ Unpacks current dir if if "./.." used
-uint cleanup_dirname(register my_string to, const char *from)
- /* to may be == from */
+ RETURN
+ # length of new name
+*/
+size_t cleanup_dirname(register char *to, const char *from)
{
- reg5 uint length;
- reg2 my_string pos;
- reg3 my_string from_ptr;
- reg4 my_string start;
+ reg5 size_t length;
+ reg2 char * pos;
+ reg3 char * from_ptr;
+ reg4 char * start;
char parent[5], /* for "FN_PARENTDIR" */
buff[FN_REFLEN+1],*end_parentdir;
#ifdef BACKSLASH_MBTAIL
@@ -130,17 +141,17 @@ uint cleanup_dirname(register my_string to, const char *from)
DBUG_PRINT("enter",("from: '%s'",from));
start=buff;
- from_ptr=(my_string) from;
+ from_ptr=(char *) from;
#ifdef FN_DEVCHAR
if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
{ /* Skip device part */
- length=(uint) (pos-from_ptr)+1;
+ length=(size_t) (pos-from_ptr)+1;
start=strnmov(buff,from_ptr,length); from_ptr+=length;
}
#endif
parent[0]=FN_LIBCHAR;
- length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
+ length=(size_t) (strmov(parent+1,FN_PARENTDIR)-parent);
for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
{
#ifdef BACKSLASH_MBTAIL
@@ -156,7 +167,7 @@ uint cleanup_dirname(register my_string to, const char *from)
*pos = FN_LIBCHAR;
if (*pos == FN_LIBCHAR)
{
- if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
+ if ((size_t) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
{ /* If .../../; skip prev */
pos-=length;
if (pos != start)
@@ -195,7 +206,7 @@ uint cleanup_dirname(register my_string to, const char *from)
}
}
}
- else if ((uint) (pos-start) == length-1 &&
+ else if ((size_t) (pos-start) == length-1 &&
!bcmp(start,parent+1,length-1))
start=pos; /* Starts with "../" */
else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
@@ -217,7 +228,7 @@ uint cleanup_dirname(register my_string to, const char *from)
}
(void) strmov(to,buff);
DBUG_PRINT("exit",("to: '%s'",to));
- DBUG_RETURN((uint) (pos-buff));
+ DBUG_RETURN((size_t) (pos-buff));
} /* cleanup_dirname */
@@ -240,7 +251,7 @@ void symdirget(char *dir)
if (dir[0] && pos[-1] != FN_DEVCHAR && my_access(dir, F_OK))
{
File file;
- uint length;
+ size_t length;
char temp= *(--pos); /* May be "/" or "\" */
strmov(pos,".sym");
file= my_open(dir, O_RDONLY, MYF(0));
@@ -257,7 +268,7 @@ void symdirget(char *dir)
if (pos == buff || pos[-1] != FN_LIBCHAR)
*pos++=FN_LIBCHAR;
- strmake(dir,buff, (uint) (pos-buff));
+ strmake(dir,buff, (size_t) (pos-buff));
}
my_close(file, MYF(0));
}
@@ -285,14 +296,14 @@ void symdirget(char *dir)
Length of new directory name (= length of to)
*/
-uint unpack_dirname(my_string to, const char *from)
+size_t unpack_dirname(char * to, const char *from)
{
- uint length,h_length;
+ size_t length, h_length;
char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
DBUG_ENTER("unpack_dirname");
- (void) intern_filename(buff,from); /* Change to intern name */
- length= (uint) strlen(buff); /* Fix that '/' is last */
+ (void) intern_filename(buff,from); /* Change to intern name */
+ length= strlen(buff); /* Fix that '/' is last */
if (length &&
#ifdef FN_DEVCHAR
buff[length-1] != FN_DEVCHAR &&
@@ -309,15 +320,15 @@ uint unpack_dirname(my_string to, const char *from)
suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
if (tilde_expansion)
{
- length-=(uint) (suffix-buff)-1;
- if (length+(h_length= (uint) strlen(tilde_expansion)) <= FN_REFLEN)
+ length-= (size_t) (suffix-buff)-1;
+ if (length+(h_length= strlen(tilde_expansion)) <= FN_REFLEN)
{
if (tilde_expansion[h_length-1] == FN_LIBCHAR)
h_length--;
if (buff+h_length < suffix)
bmove(buff+h_length,suffix,length);
else
- bmove_upp(buff+h_length+length,suffix+length,length);
+ bmove_upp((uchar*) buff+h_length+length, (uchar*) suffix+length, length);
bmove(buff,tilde_expansion,h_length);
}
}
@@ -333,7 +344,7 @@ uint unpack_dirname(my_string to, const char *from)
/* Expand tilde to home or user-directory */
/* Path is reset to point at FN_LIBCHAR after ~xxx */
-static my_string NEAR_F expand_tilde(my_string *path)
+static char * NEAR_F expand_tilde(char * *path)
{
if (path[0][0] == FN_LIBCHAR)
return home_dir; /* ~/ expanded to home */
@@ -355,7 +366,7 @@ static my_string NEAR_F expand_tilde(my_string *path)
}
}
#endif
- return (my_string) 0;
+ return (char *) 0;
}
@@ -376,13 +387,13 @@ static my_string NEAR_F expand_tilde(my_string *path)
*/
-uint unpack_filename(my_string to, const char *from)
+size_t unpack_filename(char * to, const char *from)
{
- uint length,n_length;
+ size_t length, n_length, buff_length;
char buff[FN_REFLEN];
DBUG_ENTER("unpack_filename");
- length=dirname_part(buff,from); /* copy & convert dirname */
+ length=dirname_part(buff, from, &buff_length);/* copy & convert dirname */
n_length=unpack_dirname(buff,buff);
if (n_length+strlen(from+length) < FN_REFLEN)
{
@@ -399,10 +410,10 @@ uint unpack_filename(my_string to, const char *from)
/* Used before system command's like open(), create() .. */
/* Returns length of to */
-uint system_filename(my_string to, const char *from)
+size_t system_filename(char * to, const char *from)
{
#ifndef FN_C_BEFORE_DIR
- return (uint) (strmake(to,from,FN_REFLEN-1)-to);
+ return (size_t) (strmake(to,from,FN_REFLEN-1)-to);
#else /* VMS */
/* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
@@ -412,8 +423,9 @@ uint system_filename(my_string to, const char *from)
/* change '/x/y/z to '[x.y]x' */
/* change 'dev:/x' to 'dev:[000000]x' */
- int libchar_found,length;
- my_string to_pos,from_pos,pos;
+ int libchar_found;
+ size_t length;
+ char * to_pos,from_pos,pos;
char buff[FN_REFLEN];
DBUG_ENTER("system_filename");
@@ -423,7 +435,7 @@ uint system_filename(my_string to, const char *from)
if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
{
pos++;
- to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+ to_pos=strnmov(to,from_pos,(size_t) (pos-from_pos));
from_pos=pos;
}
else
@@ -454,115 +466,30 @@ uint system_filename(my_string to, const char *from)
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_s) (pos-from_pos));
+ to_pos=strnmov(to_pos,from_pos,(size_t) (pos-from_pos));
from_pos=pos+1;
}
*(to_pos++)=FN_C_AFTER_DIR;
}
- length=(int) (strmov(to_pos,from_pos)-to);
+ length= (size_t) (strmov(to_pos,from_pos)-to);
DBUG_PRINT("exit",("name: '%s'",to));
- DBUG_RETURN((uint) length);
+ DBUG_RETURN(length);
#endif
} /* system_filename */
/* Fix a filename to intern (UNIX format) */
-my_string intern_filename(my_string to, const char *from)
+char *intern_filename(char *to, const char *from)
{
-#ifndef VMS
- {
- uint length;
- char buff[FN_REFLEN];
- if (from == to)
- { /* Dirname may destroy from */
- strmov(buff,from);
- from=buff;
- }
- length=dirname_part(to,from); /* Copy dirname & fix chars */
- (void) strcat(to,from+length);
- return (to);
- }
-#else /* VMS */
-
- /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
- /* change 'dev:xxx' to 'dev:xxx' */
- /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
- /* change '[.lib]' to './lib/' */
- /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
- /* change '[000000.x] or [x.000000]' to '/x/' */
-
- int par_length,root_length;
- my_string pos,from_pos,to_pos,end_pos;
+ size_t length, to_length;
char buff[FN_REFLEN];
-
- convert_dirname(buff,from,NullS); /* change '<>' to '[]' */
- from_pos=buff;
- if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skip device part */
- {
- pos++;
- to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
- from_pos=pos;
+ if (from == to)
+ { /* Dirname may destroy from */
+ strmov(buff,from);
+ from=buff;
}
- else
- to_pos=to;
-
- root_length=strlen(FN_C_ROOT_DIR);
- if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
- (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
- {
- to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
- /* Copy all between ':' and '[' */
- from_pos=pos+1;
- if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
- (from_pos[root_length] == FN_C_DIR_SEP ||
- from_pos[root_length] == FN_C_AFTER_DIR))
- {
- from_pos+=root_length+1;
- }
- else if (*from_pos == FN_C_DIR_SEP)
- *(to_pos++) = FN_CURLIB; /* Set ./ first */
- *(to_pos++) = FN_LIBCHAR;
-
- par_length=strlen(FN_C_PARENT_DIR);
- pos=to_pos;
- for (; from_pos <= end_pos ; from_pos++)
- {
- switch (*from_pos) {
- case FN_C_DIR_SEP:
- case FN_C_AFTER_DIR:
- if (pos != to_pos)
- {
- if ((int) (to_pos-pos) == root_length &&
- is_suffix(pos,FN_C_ROOT_DIR))
- to_pos=pos; /* remove root-pos */
- else
- {
- *(to_pos++)=FN_LIBCHAR; /* Find lib */
- pos=to_pos;
- }
- }
- break;
- case FN_C_BEFORE_DIR:
- break;
- case '-': /* *(FN_C_PARENT_DIR): */
- if (to_pos[-1] == FN_LIBCHAR &&
- strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
- { /* Change '-' to '..' */
- to_pos=strmov(to_pos,FN_PARENTDIR);
- *(to_pos++)=FN_LIBCHAR;
- pos=to_pos;
- from_pos+=par_length-1;
- break;
- }
- /* Fall through */
- default:
- *(to_pos++)= *from_pos;
- break;
- }
- }
- }
- (void) strmov(to_pos,from_pos);
+ length= dirname_part(to, from, &to_length); /* Copy dirname & fix chars */
+ (void) strmov(to + to_length,from+length);
return (to);
-#endif /* VMS */
} /* intern_filename */
diff --git a/mysys/mf_path.c b/mysys/mf_path.c
index 9af6173b417..73e73cb7f76 100644
--- a/mysys/mf_path.c
+++ b/mysys/mf_path.c
@@ -29,22 +29,24 @@ static char *find_file_in_path(char *to,const char *name);
own_path_name_part is concatinated to result.
my_path puts result in to and returns to */
-my_string my_path(my_string to, const char *progname,
- const char *own_pathname_part)
+char * my_path(char * to, const char *progname,
+ const char *own_pathname_part)
{
- my_string start,end,prog;
+ char *start, *end, *prog;
+ size_t to_length;
DBUG_ENTER("my_path");
start=to; /* Return this */
- if (progname && (dirname_part(to, progname) ||
+ if (progname && (dirname_part(to, progname, &to_length) ||
find_file_in_path(to,progname) ||
- ((prog=getenv("_")) != 0 && dirname_part(to,prog))))
+ ((prog=getenv("_")) != 0 &&
+ dirname_part(to, prog, &to_length))))
{
VOID(intern_filename(to,to));
if (!test_if_hard_path(to))
{
if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
- bchange(to,0,curr_dir, (uint) strlen(curr_dir), (uint) strlen(to)+1);
+ bchange((uchar*) to, 0, (uchar*) curr_dir, strlen(curr_dir), strlen(to)+1);
}
}
else
@@ -72,7 +74,7 @@ my_string my_path(my_string to, const char *progname,
/* test if file without filename is found in path */
/* Returns to if found and to has dirpart if found, else NullS */
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2)
+#if defined(__WIN__)
#define F_OK 0
#define PATH_SEP ';'
#define PROGRAM_EXTENSION ".exe"
diff --git a/mysys/mf_radix.c b/mysys/mf_radix.c
index 6b750181558..582ca76b8f8 100644
--- a/mysys/mf_radix.c
+++ b/mysys/mf_radix.c
@@ -25,7 +25,7 @@
/* Radixsort */
-void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_s size_of_element, uchar **buffer)
+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];
@@ -34,7 +34,7 @@ void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_s size_of
end=base+number_of_elements; count_end=count+256;
for (pass=(int) size_of_element-1 ; pass >= 0 ; pass--)
{
- bzero((gptr) count,sizeof(uint32)*256);
+ bzero((uchar*) count,sizeof(uint32)*256);
for (ptr= base ; ptr < end ; ptr++)
count[ptr[0][pass]]++;
if (count[0] == number_of_elements)
diff --git a/mysys/mf_same.c b/mysys/mf_same.c
index e7cdb012c9f..6738dc8051e 100644
--- a/mysys/mf_same.c
+++ b/mysys/mf_same.c
@@ -25,14 +25,15 @@
Returns 'to'.
*/
-my_string fn_same(char *to, const char *name, int flag)
+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),FN_EXTCHAR)) == 0)
+ if ((ext=strrchr(name+dirname_part(dev, name, &dev_length),FN_EXTCHAR)) == 0)
ext="";
DBUG_RETURN(fn_format(to,to,dev,ext,flag));
diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c
index e7fd6873eee..741c8f42327 100644
--- a/mysys/mf_sort.c
+++ b/mysys/mf_sort.c
@@ -18,7 +18,7 @@
#include "mysys_priv.h"
#include <m_string.h>
-void my_string_ptr_sort(void *base, uint items, size_s size)
+void my_string_ptr_sort(uchar *base, uint items, size_t size)
{
#if INT_MAX > 65536L
uchar **ptr=0;
@@ -27,15 +27,15 @@ void my_string_ptr_sort(void *base, uint items, size_s size)
(ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
{
radixsort_for_str_ptr((uchar**) base,items,size,ptr);
- my_free((gptr) ptr,MYF(0));
+ my_free((uchar*) ptr,MYF(0));
}
else
#endif
{
if (size && items)
{
- uint size_arg=size;
- qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg);
+ qsort2(base,items, sizeof(uchar*), get_ptr_compare(size),
+ (void*) &size);
}
}
}
diff --git a/mysys/mf_soundex.c b/mysys/mf_soundex.c
index fa393d1a94a..fe30d8c81af 100644
--- a/mysys/mf_soundex.c
+++ b/mysys/mf_soundex.c
@@ -42,11 +42,11 @@ 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 my_string out_pntr, my_string in_pntr,
+void soundex(CHARSET_INFO * cs,register char * out_pntr, char * in_pntr,
pbool remove_garbage)
{
char ch,last_ch;
- reg3 my_string end;
+ reg3 char * end;
register uchar *map=cs->to_upper;
if (remove_garbage)
diff --git a/mysys/mf_strip.c b/mysys/mf_strip.c
index 712b0e1d28a..b33620b1b2d 100644
--- a/mysys/mf_strip.c
+++ b/mysys/mf_strip.c
@@ -18,14 +18,14 @@
#include "mysys_priv.h"
/*
- strip_sp(my_string str)
+ strip_sp(char * str)
Strips end-space from string and returns new length.
*/
-size_s strip_sp(register my_string str)
+size_t strip_sp(register char * str)
{
- reg2 my_string found;
- reg3 my_string start;
+ reg2 char * found;
+ reg3 char * start;
start=found=str;
@@ -35,11 +35,11 @@ size_s strip_sp(register my_string str)
{
while (*++str && *str != ' ') {};
if (!*str)
- return (size_s) (str-start); /* Return stringlength */
+ return (size_t) (str-start); /* Return stringlength */
}
found=str;
while (*++str == ' ') {};
}
*found= '\0'; /* Stripp at first space */
- return (size_s) (found-start);
+ return (size_t) (found-start);
} /* strip_sp */
diff --git a/mysys/mf_tempdir.c b/mysys/mf_tempdir.c
index bcd003920f1..b2c18c74347 100644
--- a/mysys/mf_tempdir.c
+++ b/mysys/mf_tempdir.c
@@ -16,7 +16,7 @@
#include "mysys_priv.h"
#include <m_string.h>
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined( __WIN__) || defined(__NETWARE__)
#define DELIM ';'
#else
#define DELIM ':'
@@ -26,14 +26,17 @@ 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"));
+
pthread_mutex_init(&tmpdir->mutex, MY_MUTEX_INIT_FAST);
if (my_init_dynamic_array(&tmpdir->full_list, sizeof(char*), 1, 5))
- return TRUE;
+ goto err;
if (!pathlist || !pathlist[0])
{
/* Get default temporary directory */
pathlist=getenv("TMPDIR"); /* Use this if possible */
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined( __WIN__) || defined(__NETWARE__)
if (!pathlist)
pathlist=getenv("TEMP");
if (!pathlist)
@@ -44,12 +47,13 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist)
}
do
{
+ uint length;
end=strcend(pathlist, DELIM);
- convert_dirname(buff, pathlist, end);
- if (!(copy=my_strdup(buff, MYF(MY_WME))))
- return TRUE;
- if (insert_dynamic(&tmpdir->full_list, (gptr)&copy))
- return TRUE;
+ 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*) &copy))
+ DBUG_RETURN(TRUE);
pathlist=end+1;
}
while (*end);
@@ -57,12 +61,20 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist)
tmpdir->list=(char **)tmpdir->full_list.buffer;
tmpdir->max=tmpdir->full_list.elements-1;
tmpdir->cur=0;
- return FALSE;
+ DBUG_RETURN(FALSE);
+
+err:
+ delete_dynamic(&tmpdir->full_list); /* Safe to free */
+ pthread_mutex_destroy(&tmpdir->mutex);
+ DBUG_RETURN(TRUE);
}
+
char *my_tmpdir(MY_TMPDIR *tmpdir)
{
char *dir;
+ if (!tmpdir->max)
+ return tmpdir->list[0];
pthread_mutex_lock(&tmpdir->mutex);
dir=tmpdir->list[tmpdir->cur];
tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1;
diff --git a/mysys/mf_unixpath.c b/mysys/mf_unixpath.c
index 11292e231ba..75f8de14879 100644
--- a/mysys/mf_unixpath.c
+++ b/mysys/mf_unixpath.c
@@ -19,7 +19,7 @@
/* convert filename to unix style filename */
/* If MSDOS converts '\' to '/' */
-void to_unix_path(my_string to __attribute__((unused)))
+void to_unix_path(char * to __attribute__((unused)))
{
#if FN_LIBCHAR != '/'
{
diff --git a/mysys/mf_wfile.c b/mysys/mf_wfile.c
index b574d158b9e..f98d348994e 100644
--- a/mysys/mf_wfile.c
+++ b/mysys/mf_wfile.c
@@ -29,12 +29,12 @@
/* Store wildcard-string in a easyer format */
-WF_PACK *wf_comp(my_string str)
+WF_PACK *wf_comp(char * str)
{
uint ant;
int not_pos;
- register my_string pos;
- my_string buffer;
+ register char * pos;
+ char * buffer;
WF_PACK *ret;
DBUG_ENTER("wf_comp");
@@ -53,13 +53,13 @@ WF_PACK *wf_comp(my_string str)
for (pos=str ; *pos ; pos++)
ant+= test(*pos == ' ' || *pos == ',');
- if ((ret= (WF_PACK*) my_malloc((uint) ant*(sizeof(my_string*)+2)+
+ if ((ret= (WF_PACK*) my_malloc((uint) ant*(sizeof(char **)+2)+
sizeof(WF_PACK)+ (uint) strlen(str)+1,
MYF(MY_WME)))
== 0)
DBUG_RETURN((WF_PACK *) NULL);
- ret->wild= (my_string*) (ret+1);
- buffer= (my_string) (ret->wild+ant);
+ ret->wild= (char **) (ret+1);
+ buffer= (char *) (ret->wild+ant);
ant=0;
for (pos=str ; *pos ; str= pos)
@@ -119,6 +119,6 @@ void wf_end(WF_PACK *buffer)
{
DBUG_ENTER("wf_end");
if (buffer)
- my_free((gptr) buffer,MYF(0));
+ my_free((uchar*) buffer,MYF(0));
DBUG_VOID_RETURN;
} /* wf_end */
diff --git a/mysys/mulalloc.c b/mysys/mulalloc.c
index bada0a55a6a..f4ca3d9f9ab 100644
--- a/mysys/mulalloc.c
+++ b/mysys/mulalloc.c
@@ -31,11 +31,11 @@
NULL
*/
-gptr my_multi_malloc(myf myFlags, ...)
+void* my_multi_malloc(myf myFlags, ...)
{
va_list args;
char **ptr,*start,*res;
- uint tot_length,length;
+ size_t tot_length,length;
DBUG_ENTER("my_multi_malloc");
va_start(args,myFlags);
@@ -59,5 +59,5 @@ gptr my_multi_malloc(myf myFlags, ...)
res+=ALIGN_SIZE(length);
}
va_end(args);
- DBUG_RETURN((gptr) start);
+ DBUG_RETURN((void*) start);
}
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 9ee20cc942b..210946d50a8 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -53,24 +53,111 @@ int my_access(const char *path, int amode)
#endif /* __WIN__ */
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
/*
List of file names that causes problem on windows
NOTE that one can also not have file names of type CON.TXT
+
+ NOTE: it is important to keep "CLOCK$" on the first place,
+ we skip it in check_if_legal_tablename.
*/
-
static const char *reserved_names[]=
{
- "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
- "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6",
- "LPT7", "LPT8", "LPT9", "CLOCK$",
+ "CLOCK$",
+ "CON", "PRN", "AUX", "NUL",
+ "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
NullS
};
#define MAX_RESERVED_NAME_LENGTH 6
+
+/*
+ Looks up a null-terminated string in a list,
+ case insensitively.
+
+ SYNOPSIS
+ str_list_find()
+ list list of items
+ str item to find
+
+ RETURN
+ 0 ok
+ 1 reserved file name
+*/
+static int str_list_find(const char **list, const char *str)
+{
+ const char **name;
+ for (name= list; *name; name++)
+ {
+ if (!my_strcasecmp(&my_charset_latin1, *name, str))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ A map for faster reserved_names lookup,
+ helps to avoid loops in many cases.
+ 1 - can be the first letter
+ 2 - can be the second letter
+ 4 - can be the third letter
+*/
+static char reserved_map[256]=
+{
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* !"#$%&'()*+,-./ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0123456789:;<=>? */
+ 0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* @ABCDEFGHIJKLMNO */
+ 3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* PQRSTUVWXYZ[\]^_ */
+ 0,1,0,1,0,0,0,0,0,0,0,0,7,4,5,2, /* bcdefghijklmno */
+ 3,0,2,0,4,2,0,0,4,0,0,0,0,0,0,0, /* pqrstuvwxyz{|}~. */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ................ */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ................ */
+};
+
+
+/*
+ Check if a table name may cause problems
+
+ SYNOPSIS
+ check_if_legal_tablename
+ name Table name (without any extensions)
+
+ DESCRIPTION
+ We don't check 'CLOCK$' because dollar sign is encoded as @0024,
+ making table file name 'CLOCK@0024', which is safe.
+ This is why we start lookup from the second element
+ (i.e. &reserver_name[1])
+
+ RETURN
+ 0 ok
+ 1 reserved file name
+*/
+
+int check_if_legal_tablename(const char *name)
+{
+ DBUG_ENTER("check_if_legal_tablename");
+ DBUG_RETURN((reserved_map[(uchar) name[0]] & 1) &&
+ (reserved_map[(uchar) name[1]] & 2) &&
+ (reserved_map[(uchar) name[2]] & 4) &&
+ str_list_find(&reserved_names[1], name));
+}
+
+
+#if defined(__WIN__) || defined(__EMX__)
+
+
/*
Check if a path will access a reserverd file name that may cause problems
@@ -110,12 +197,5 @@ int check_if_legal_filename(const char *path)
}
DBUG_RETURN(0);
}
-#endif
-
-#ifdef OS2
-int check_if_legal_filename(const char *path)
-{
- return 0;
-}
-#endif /* OS2 */
+#endif /* defined(__WIN__) || defined(__EMX__) */
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index 5983a29a3e1..9203ce9c34e 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -43,8 +43,8 @@
reported as error in first alloc_root() on this memory root.
*/
-void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
- uint pre_alloc_size __attribute__((unused)))
+void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
+ size_t pre_alloc_size __attribute__((unused)))
{
DBUG_ENTER("init_alloc_root");
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
@@ -90,8 +90,8 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
before allocation.
*/
-void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
- uint pre_alloc_size __attribute__((unused)))
+void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
+ size_t pre_alloc_size __attribute__((unused)))
{
DBUG_ASSERT(alloc_root_inited(mem_root));
@@ -99,7 +99,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size)
{
- uint size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
+ size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
{
USED_MEM *mem, **prev= &mem_root->free;
@@ -120,7 +120,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
{
/* remove block from the list and free it */
*prev= mem->next;
- my_free((gptr) mem, MYF(0));
+ my_free(mem, MYF(0));
}
else
prev= &mem->next;
@@ -145,7 +145,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
}
-gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
+void *alloc_root(MEM_ROOT *mem_root, size_t length)
{
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
reg1 USED_MEM *next;
@@ -154,32 +154,32 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
DBUG_ASSERT(alloc_root_inited(mem_root));
- Size+=ALIGN_SIZE(sizeof(USED_MEM));
- if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
+ length+=ALIGN_SIZE(sizeof(USED_MEM));
+ if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME))))
{
if (mem_root->error_handler)
(*mem_root->error_handler)();
- DBUG_RETURN((gptr) 0); /* purecov: inspected */
+ DBUG_RETURN((uchar*) 0); /* purecov: inspected */
}
next->next= mem_root->used;
- next->size= Size;
+ next->size= length;
mem_root->used= next;
DBUG_PRINT("exit",("ptr: 0x%lx", (long) (((char*) next)+
ALIGN_SIZE(sizeof(USED_MEM)))));
- DBUG_RETURN((gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
+ DBUG_RETURN((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
#else
- uint get_size, block_size;
- gptr point;
+ size_t get_size, block_size;
+ uchar* point;
reg1 USED_MEM *next= 0;
reg2 USED_MEM **prev;
DBUG_ENTER("alloc_root");
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
DBUG_ASSERT(alloc_root_inited(mem_root));
- Size= ALIGN_SIZE(Size);
+ length= ALIGN_SIZE(length);
if ((*(prev= &mem_root->free)) != NULL)
{
- if ((*prev)->left < Size &&
+ if ((*prev)->left < length &&
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
{
@@ -189,20 +189,20 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
mem_root->used= next;
mem_root->first_block_usage= 0;
}
- for (next= *prev ; next && next->left < Size ; next= next->next)
+ for (next= *prev ; next && next->left < length ; next= next->next)
prev= &next->next;
}
if (! next)
{ /* Time to alloc new block */
block_size= mem_root->block_size * (mem_root->block_num >> 2);
- get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+ 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 (mem_root->error_handler)
(*mem_root->error_handler)();
- return((gptr) 0); /* purecov: inspected */
+ return((void*) 0); /* purecov: inspected */
}
mem_root->block_num++;
next->next= *prev;
@@ -211,9 +211,9 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
*prev=next;
}
- point= (gptr) ((char*) next+ (next->size-next->left));
+ point= (uchar*) ((char*) next+ (next->size-next->left));
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
- if ((next->left-= Size) < mem_root->min_malloc)
+ if ((next->left-= length) < mem_root->min_malloc)
{ /* Full block */
*prev= next->next; /* Remove block from list */
next->next= mem_root->used;
@@ -221,7 +221,7 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
mem_root->first_block_usage= 0;
}
DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point));
- DBUG_RETURN(point);
+ DBUG_RETURN((void*) point);
#endif
}
@@ -245,11 +245,11 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
in case of success or NULL if out of memory.
*/
-gptr multi_alloc_root(MEM_ROOT *root, ...)
+void *multi_alloc_root(MEM_ROOT *root, ...)
{
va_list args;
char **ptr, *start, *res;
- uint tot_length, length;
+ size_t tot_length, length;
DBUG_ENTER("multi_alloc_root");
va_start(args, root);
@@ -273,7 +273,7 @@ gptr multi_alloc_root(MEM_ROOT *root, ...)
res+= ALIGN_SIZE(length);
}
va_end(args);
- DBUG_RETURN((gptr) start);
+ DBUG_RETURN((void*) start);
}
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
@@ -334,8 +334,6 @@ void free_root(MEM_ROOT *root, myf MyFlags)
DBUG_ENTER("free_root");
DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags));
- if (!root) /* QQ: Should be deleted */
- DBUG_VOID_RETURN; /* purecov: inspected */
if (MyFlags & MY_MARK_BLOCKS_FREE)
{
mark_blocks_free(root);
@@ -348,13 +346,13 @@ void free_root(MEM_ROOT *root, myf MyFlags)
{
old=next; next= next->next ;
if (old != root->pre_alloc)
- my_free((gptr) old,MYF(0));
+ my_free(old,MYF(0));
}
for (next=root->free ; next ;)
{
old=next; next= next->next;
if (old != root->pre_alloc)
- my_free((gptr) old,MYF(0));
+ my_free(old,MYF(0));
}
root->used=root->free=0;
if (root->pre_alloc)
@@ -395,12 +393,13 @@ void set_prealloc_root(MEM_ROOT *root, char *ptr)
}
-char *strdup_root(MEM_ROOT *root,const char *str)
+char *strdup_root(MEM_ROOT *root, const char *str)
{
- return strmake_root(root, str, (uint) strlen(str));
+ return strmake_root(root, str, strlen(str));
}
-char *strmake_root(MEM_ROOT *root,const char *str, uint len)
+
+char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
{
char *pos;
if ((pos=alloc_root(root,len+1)))
@@ -412,7 +411,7 @@ char *strmake_root(MEM_ROOT *root,const char *str, uint len)
}
-char *memdup_root(MEM_ROOT *root,const char *str,uint len)
+void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
{
char *pos;
if ((pos=alloc_root(root,len)))
diff --git a/mysys/my_append.c b/mysys/my_append.c
index 274f2110575..35881a959d5 100644
--- a/mysys/my_append.c
+++ b/mysys/my_append.c
@@ -13,7 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
#include <sys/stat.h>
#include <m_string.h>
@@ -28,21 +27,22 @@ struct utimbuf {
};
#endif
- /* Append a file to another */
-
-int my_append(const char *from, const char *to, myf MyFlags)
+/*
+ Append a file to another
+ NOTES
+ Don't set MY_FNABP or MY_NABP bits on when calling this function
+*/
- /* Dont set MY_FNABP or MY_NABP bits on
- when calling this funktion */
+int my_append(const char *from, const char *to, myf MyFlags)
{
uint Count;
File from_file,to_file;
- char buff[IO_SIZE];
+ uchar buff[IO_SIZE];
DBUG_ENTER("my_append");
DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
- from_file=to_file= -1;
+ from_file= to_file= -1;
if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0)
{
diff --git a/mysys/my_atomic.c b/mysys/my_atomic.c
new file mode 100644
index 00000000000..6a30267eb80
--- /dev/null
+++ b/mysys/my_atomic.c
@@ -0,0 +1,46 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+#ifndef HAVE_INLINE
+/*
+ the following will cause all inline functions to be instantiated
+*/
+#define HAVE_INLINE
+#define static extern
+#endif
+
+#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()
+{
+ DBUG_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
+}
+
diff --git a/mysys/my_bit.c b/mysys/my_bit.c
index 81d63246e7a..5a9b1187c83 100644
--- a/mysys/my_bit.c
+++ b/mysys/my_bit.c
@@ -75,3 +75,33 @@ uint my_count_bits_ushort(ushort v)
return nbits[v];
}
+
+/*
+ Next highest power of two
+
+ SYNOPSIS
+ my_round_up_to_next_power()
+ v Value to check
+
+ RETURN
+ Next or equal power of 2
+ Note: 0 will return 0
+
+ NOTES
+ Algorithm by Sean Anderson, according to:
+ http://graphics.stanford.edu/~seander/bithacks.html
+ (Orignal code public domain)
+
+ Comments shows how this works with 01100000000000000000000000001011
+*/
+
+uint32 my_round_up_to_next_power(uint32 v)
+{
+ v--; /* 01100000000000000000000000001010 */
+ v|= v >> 1; /* 01110000000000000000000000001111 */
+ v|= v >> 2; /* 01111100000000000000000000001111 */
+ v|= v >> 4; /* 01111111110000000000000000001111 */
+ v|= v >> 8; /* 01111111111111111100000000001111 */
+ v|= v >> 16; /* 01111111111111111111111111111111 */
+ return v+1; /* 10000000000000000000000000000000 */
+}
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index beb67bb419b..10eff40b9ed 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -19,26 +19,69 @@
API limitations (or, rather asserted safety assumptions,
to encourage correct programming)
- * the size of the used bitmap is less than ~(uint) 0
- * it's a multiple of 8 (for efficiency reasons)
- * when arguments are a bitmap and a bit number, the number
- must be within bitmap size
- * bitmap_set_prefix() is an exception - one can use ~0 to set all bits
- * when both arguments are bitmaps, they must be of the same size
- * bitmap_intersect() is an exception :)
- (for for Bitmap::intersect(ulonglong map2buff))
-
- If THREAD is defined all bitmap operations except bitmap_init/bitmap_free
- are thread-safe.
+ * 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_*
+ many of those are not used and not compiled normally but the code
+ already exist for them in an #ifdef:ed part. These can only be used
+ if THREAD was specified in bitmap_init
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>
+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)))
{
#ifdef THREAD
@@ -56,29 +99,43 @@ static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
}
-my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
- my_bool thread_safe)
+my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
+ my_bool thread_safe __attribute__((unused)))
{
DBUG_ENTER("bitmap_init");
-
- DBUG_ASSERT((bitmap_size & 7) == 0);
- bitmap_size/=8;
- if (!(map->bitmap=buf) &&
- !(map->bitmap= (uchar*) my_malloc(bitmap_size +
- (thread_safe ?
- sizeof(pthread_mutex_t) : 0),
- MYF(MY_WME | MY_ZEROFILL))))
- DBUG_RETURN(1);
- map->bitmap_size=bitmap_size;
-#ifdef THREAD
- if (thread_safe)
+ if (!buf)
{
- map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size);
- pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
+ uint size_in_bytes= bitmap_buffer_size(n_bits);
+ uint extra= 0;
+#ifdef THREAD
+ if (thread_safe)
+ {
+ size_in_bytes= ALIGN_SIZE(size_in_bytes);
+ extra= sizeof(pthread_mutex_t);
+ }
+ map->mutex= 0;
+#endif
+ if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
+ DBUG_RETURN(1);
+#ifdef THREAD
+ if (thread_safe)
+ {
+ map->mutex= (pthread_mutex_t *) ((char*) buf + size_in_bytes);
+ pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
+ }
+#endif
}
+#ifdef THREAD
else
- map->mutex=0;
+ {
+ DBUG_ASSERT(thread_safe == 0);
+ }
#endif
+
+ map->bitmap= buf;
+ map->n_bits= n_bits;
+ create_last_word_mask(map);
+ bitmap_clear_all(map);
DBUG_RETURN(0);
}
@@ -99,15 +156,6 @@ void bitmap_free(MY_BITMAP *map)
}
-void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
-{
- DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
- bitmap_lock(map);
- bitmap_fast_set_bit(map, bitmap_bit);
- bitmap_unlock(map);
-}
-
-
/*
test if bit already set and set it if it was not (thread unsafe method)
@@ -123,7 +171,7 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
{
- uchar *value= map->bitmap + (bitmap_bit / 8);
+ uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
uchar bit= 1 << ((bitmap_bit) & 7);
uchar res= (*value) & bit;
*value|= bit;
@@ -147,182 +195,177 @@ my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
{
my_bool res;
- DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
+ 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;
}
-uint bitmap_set_next(MY_BITMAP *map)
-{
- uchar *bitmap=map->bitmap;
- uint bit_found = MY_BIT_NONE;
- uint bitmap_size=map->bitmap_size;
- uint i;
+/*
+ test if bit already set and clear it if it was set(thread unsafe method)
- DBUG_ASSERT(map->bitmap);
- bitmap_lock(map);
- for (i=0; i < bitmap_size ; i++, bitmap++)
- {
- if (*bitmap != 0xff)
- { /* Found slot with free bit */
- uint b;
- for (b=0; ; b++)
- {
- if (!(*bitmap & (1 << b)))
- {
- *bitmap |= 1<<b;
- bit_found = (i*8)+b;
- break;
- }
- }
- break; /* Found bit */
- }
- }
- bitmap_unlock(map);
- return bit_found;
-}
+ SYNOPSIS
+ bitmap_fast_test_and_set()
+ MAP bit map struct
+ BIT bit number
+ RETURN
+ 0 bit was not set
+ !=0 bit was set
+*/
-void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
+my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
{
- DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
- bitmap_lock(map);
- bitmap_fast_clear_bit(map, bitmap_bit);
- bitmap_unlock(map);
+ uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
+ uchar bit= 1 << ((bitmap_bit) & 7);
+ uchar res= (*byte) & bit;
+ *byte&= ~bit;
+ return res;
}
-void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
+my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
{
- uint prefix_bytes, prefix_bits;
-
- DBUG_ASSERT(map->bitmap &&
- (prefix_size <= map->bitmap_size*8 || prefix_size == (uint) ~0));
+ my_bool res;
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
bitmap_lock(map);
- set_if_smaller(prefix_size, map->bitmap_size*8);
- if ((prefix_bytes= prefix_size / 8))
- memset(map->bitmap, 0xff, prefix_bytes);
- if ((prefix_bits= prefix_size & 7))
- map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1;
- if (prefix_bytes < map->bitmap_size)
- bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes);
+ res= bitmap_fast_test_and_clear(map, bitmap_bit);
bitmap_unlock(map);
+ return res;
}
-void bitmap_clear_all(MY_BITMAP *map)
+uint bitmap_set_next(MY_BITMAP *map)
{
- bitmap_set_prefix(map, 0);
+ 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_all(MY_BITMAP *map)
+void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
- bitmap_set_prefix(map, ~0);
+ 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 & 7, res= 0;
- uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8,
- *end= map->bitmap+map->bitmap_size;
-
- DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8);
+ 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);
- bitmap_lock((MY_BITMAP *)map);
while (m < end_prefix)
if (*m++ != 0xff)
- goto ret;
+ 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;
+ res= 1;
ret:
- bitmap_unlock((MY_BITMAP *)map);
- return res;
+ return res;
}
-my_bool bitmap_is_clear_all(const MY_BITMAP *map)
-{
- return bitmap_is_prefix(map, 0);
-}
-
my_bool bitmap_is_set_all(const MY_BITMAP *map)
{
- return bitmap_is_prefix(map, map->bitmap_size*8);
+ 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_set(const MY_BITMAP *map, uint bitmap_bit)
+my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
- DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
- return bitmap_fast_is_set(map, bitmap_bit);
+ 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)
{
- uint res=0;
- uchar *m1=map1->bitmap, *m2=map2->bitmap, *end;
+ my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
- map1->bitmap_size==map2->bitmap_size);
- bitmap_lock((MY_BITMAP *)map1);
- bitmap_lock((MY_BITMAP *)map2);
+ map1->n_bits==map2->n_bits);
- end= m1+map1->bitmap_size;
-
- while (m1 < end)
+ 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++))
- goto ret;
+ return 0;
}
-
- res=1;
-ret:
- bitmap_unlock((MY_BITMAP *)map2);
- bitmap_unlock((MY_BITMAP *)map1);
- return res;
+ return 1;
}
+/* True if bitmaps has any common bits */
-my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
+my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
- uint res;
+ my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
- map1->bitmap_size==map2->bitmap_size);
- bitmap_lock((MY_BITMAP *)map1);
- bitmap_lock((MY_BITMAP *)map2);
-
- res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0;
+ map1->n_bits==map2->n_bits);
- bitmap_unlock((MY_BITMAP *)map2);
- bitmap_unlock((MY_BITMAP *)map1);
- return res;
+ 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)
{
- uchar *to=map->bitmap, *from=map2->bitmap, *end;
- uint len=map->bitmap_size, len2=map2->bitmap_size;
+ 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);
- bitmap_lock(map);
- bitmap_lock((MY_BITMAP *)map2);
end= to+min(len,len2);
-
+ *map2->last_word_ptr&= ~map2->last_word_mask; /*Clear last bits in map2*/
while (to < end)
*to++ &= *from++;
@@ -332,9 +375,6 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
while (to < end)
*to++=0;
}
-
- bitmap_unlock((MY_BITMAP *)map2);
- bitmap_unlock(map);
}
@@ -361,8 +401,8 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
{
uchar use_byte= use_bit ? 0xff : 0;
- uchar *to= map->bitmap + from_byte;
- uchar *end= map->bitmap + map->bitmap_size;
+ uchar *to= (uchar *)map->bitmap + from_byte;
+ uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
while (to < end)
*to++= use_byte;
@@ -371,37 +411,283 @@ void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
{
- uchar *to=map->bitmap, *from=map2->bitmap, *end;
+ 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->bitmap_size==map2->bitmap_size);
+ 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;
+ }
+ DBUG_ASSERT(0);
+ }
+ }
+ DBUG_ASSERT(0);
+ }
+ }
+ 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;
+ }
+ DBUG_ASSERT(0);
+ }
+ }
+ DBUG_ASSERT(0);
+ }
+ }
+ return MY_BIT_NONE;
+}
+
+
+uint bitmap_lock_set_next(MY_BITMAP *map)
+{
+ uint bit_found;
bitmap_lock(map);
- bitmap_lock((MY_BITMAP *)map2);
+ bit_found= bitmap_set_next(map);
+ bitmap_unlock(map);
+ return bit_found;
+}
- end= to+map->bitmap_size;
- while (to < end)
- *to++ &= ~(*from++);
+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);
+}
- bitmap_unlock((MY_BITMAP *)map2);
+
+#ifdef NOT_USED
+my_bool bitmap_lock_is_prefix(const MY_BITMAP *map, uint prefix_size)
+{
+ my_bool res;
+ bitmap_lock((MY_BITMAP *)map);
+ res= bitmap_is_prefix(map, prefix_size);
+ bitmap_unlock((MY_BITMAP *)map);
+ return res;
+}
+
+
+void bitmap_lock_set_all(MY_BITMAP *map)
+{
+ bitmap_lock(map);
+ bitmap_set_all(map);
bitmap_unlock(map);
}
-void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
+void bitmap_lock_clear_all(MY_BITMAP *map)
{
- uchar *to=map->bitmap, *from=map2->bitmap, *end;
+ bitmap_lock(map);
+ bitmap_clear_all(map);
+ bitmap_unlock(map);
+}
- DBUG_ASSERT(map->bitmap && map2->bitmap &&
- map->bitmap_size==map2->bitmap_size);
+
+void bitmap_lock_set_prefix(MY_BITMAP *map, uint prefix_size)
+{
+ bitmap_lock(map);
+ bitmap_set_prefix(map, prefix_size);
+ bitmap_unlock(map);
+}
+
+
+my_bool bitmap_lock_is_clear_all(const MY_BITMAP *map)
+{
+ uint res;
+ bitmap_lock((MY_BITMAP *)map);
+ res= bitmap_is_clear_all(map);
+ bitmap_unlock((MY_BITMAP *)map);
+ return res;
+}
+
+
+my_bool bitmap_lock_is_set_all(const MY_BITMAP *map)
+{
+ uint res;
+ bitmap_lock((MY_BITMAP *)map);
+ res= bitmap_is_set_all(map);
+ bitmap_unlock((MY_BITMAP *)map);
+ return res;
+}
+
+
+my_bool bitmap_lock_is_set(const MY_BITMAP *map, uint bitmap_bit)
+{
+ my_bool res;
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
+ bitmap_lock((MY_BITMAP *)map);
+ res= bitmap_is_set(map, bitmap_bit);
+ bitmap_unlock((MY_BITMAP *)map);
+ return res;
+}
+
+
+my_bool bitmap_lock_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
+{
+ uint res;
+ bitmap_lock((MY_BITMAP *)map1);
+ bitmap_lock((MY_BITMAP *)map2);
+ res= bitmap_is_subset(map1, map2);
+ bitmap_unlock((MY_BITMAP *)map2);
+ bitmap_unlock((MY_BITMAP *)map1);
+ return res;
+}
+
+
+my_bool bitmap_lock_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
+{
+ uint res;
+
+ DBUG_ASSERT(map1->bitmap && map2->bitmap &&
+ map1->n_bits==map2->n_bits);
+ bitmap_lock((MY_BITMAP *)map1);
+ bitmap_lock((MY_BITMAP *)map2);
+ res= bitmap_cmp(map1, map2);
+ bitmap_unlock((MY_BITMAP *)map2);
+ bitmap_unlock((MY_BITMAP *)map1);
+ return res;
+}
+
+
+void bitmap_lock_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
+{
bitmap_lock(map);
bitmap_lock((MY_BITMAP *)map2);
+ bitmap_intersect(map, map2);
+ bitmap_unlock((MY_BITMAP *)map2);
+ bitmap_unlock(map);
+}
- end= to+map->bitmap_size;
- while (to < end)
- *to++ |= *from++;
+void bitmap_lock_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
+{
+ bitmap_lock(map);
+ bitmap_lock((MY_BITMAP *)map2);
+ bitmap_subtract(map, map2);
+ bitmap_unlock((MY_BITMAP *)map2);
+ bitmap_unlock(map);
+}
+
+void bitmap_lock_union(MY_BITMAP *map, const MY_BITMAP *map2)
+{
+ bitmap_lock(map);
+ bitmap_lock((MY_BITMAP *)map2);
+ bitmap_union(map, map2);
bitmap_unlock((MY_BITMAP *)map2);
bitmap_unlock(map);
}
@@ -414,19 +700,12 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
RETURN
Number of set bits in the bitmap.
*/
-
-uint bitmap_bits_set(const MY_BITMAP *map)
-{
- uchar *m= map->bitmap;
- uchar *end= m + map->bitmap_size;
- uint res= 0;
-
- DBUG_ASSERT(map->bitmap);
+uint bitmap_lock_bits_set(const MY_BITMAP *map)
+{
+ uint res;
bitmap_lock((MY_BITMAP *)map);
- while (m < end)
- {
- res+= my_count_bits_ushort(*m++);
- }
+ DBUG_ASSERT(map->bitmap);
+ res= bitmap_bits_set(map);
bitmap_unlock((MY_BITMAP *)map);
return res;
}
@@ -439,33 +718,412 @@ uint bitmap_bits_set(const MY_BITMAP *map)
RETURN
Number of first unset bit in the bitmap or MY_BIT_NONE if all bits are set.
*/
+uint bitmap_lock_get_first(const MY_BITMAP *map)
+{
+ uint res;
+ bitmap_lock((MY_BITMAP*)map);
+ res= bitmap_get_first(map);
+ bitmap_unlock((MY_BITMAP*)map);
+ return res;
+}
-uint bitmap_get_first(const MY_BITMAP *map)
+
+uint bitmap_lock_get_first_set(const MY_BITMAP *map)
+{
+ uint res;
+ bitmap_lock((MY_BITMAP*)map);
+ res= bitmap_get_first_set(map);
+ bitmap_unlock((MY_BITMAP*)map);
+ return res;
+}
+
+
+void bitmap_lock_set_bit(MY_BITMAP *map, uint bitmap_bit)
+{
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
+ bitmap_lock(map);
+ bitmap_set_bit(map, bitmap_bit);
+ bitmap_unlock(map);
+}
+
+
+void bitmap_lock_flip_bit(MY_BITMAP *map, uint bitmap_bit)
+{
+ DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
+ bitmap_lock(map);
+ bitmap_flip_bit(map, bitmap_bit);
+ bitmap_unlock(map);
+}
+#endif
+#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)
{
- uchar *bitmap=map->bitmap;
- uint bit_found = MY_BIT_NONE;
- uint bitmap_size=map->bitmap_size;
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;
+}
- DBUG_ASSERT(map->bitmap);
- bitmap_lock((MY_BITMAP *)map);
- for (i=0; i < bitmap_size ; i++, bitmap++)
+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++)
{
- if (*bitmap != 0xff)
- { /* Found slot with free bit */
- uint b;
- for (b=0; ; b++)
- {
- if (!(*bitmap & (1 << b)))
- {
- bit_found = (i*8)+b;
- break;
- }
- }
- break; /* Found bit */
+ 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);
}
- bitmap_unlock((MY_BITMAP *)map);
- return bit_found;
+ 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
diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c
index a5dd1564692..b1dbb22c687 100644
--- a/mysys/my_chsize.c
+++ b/mysys/my_chsize.c
@@ -40,12 +40,12 @@
int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
{
my_off_t oldsize;
- char buff[IO_SIZE];
+ uchar buff[IO_SIZE];
DBUG_ENTER("my_chsize");
DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength,
MyFlags));
- if ((oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE))) == newlength)
+ if ((oldsize= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE))) == newlength)
DBUG_RETURN(0);
DBUG_PRINT("info",("old_size: %ld", (ulong) oldsize));
@@ -98,11 +98,11 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
bfill(buff, IO_SIZE, filler);
while (newlength-oldsize > IO_SIZE)
{
- if (my_write(fd,(byte*) buff,IO_SIZE,MYF(MY_NABP)))
+ if (my_write(fd, buff, IO_SIZE, MYF(MY_NABP)))
goto err;
oldsize+= IO_SIZE;
}
- if (my_write(fd,(byte*) buff,(uint) (newlength-oldsize),MYF(MY_NABP)))
+ if (my_write(fd,buff,(size_t) (newlength-oldsize), MYF(MY_NABP)))
goto err;
DBUG_RETURN(0);
diff --git a/mysys/my_clock.c b/mysys/my_clock.c
index c5fa516a622..adc755028d5 100644
--- a/mysys/my_clock.c
+++ b/mysys/my_clock.c
@@ -13,17 +13,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES
#include "my_global.h"
-#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(OS2) && !defined(__NETWARE__)
+#if !defined(_MSC_VER) && !defined(__BORLANDC__) && !defined(__NETWARE__)
#include "mysys_priv.h"
#include <sys/times.h>
#endif
long my_clock(void)
{
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
struct tms tmsbuf;
VOID(times(&tmsbuf));
return (tmsbuf.tms_utime + tmsbuf.tms_stime);
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
index c054bf155b1..bc9f8317487 100644
--- a/mysys/my_compress.c
+++ b/mysys/my_compress.c
@@ -24,12 +24,20 @@
#include <zlib.h>
/*
-** This replaces the packet with a compressed packet
-** Returns 1 on error
-** *complen is 0 if the packet wasn't compressed
+ This replaces the packet with a compressed packet
+
+ SYNOPSIS
+ my_compress()
+ packet Data to compress. This is is replaced with the compressed data.
+ len Length of data to compress at 'packet'
+ complen out: 0 if packet was not compressed
+
+ RETURN
+ 1 error. 'len' is not changed'
+ 0 ok. In this case 'len' contains the size of the compressed packet
*/
-my_bool my_compress(byte *packet, ulong *len, ulong *complen)
+my_bool my_compress(uchar *packet, size_t *len, size_t *complen)
{
DBUG_ENTER("my_compress");
if (*len < MIN_COMPRESS_LENGTH)
@@ -39,27 +47,36 @@ my_bool my_compress(byte *packet, ulong *len, ulong *complen)
}
else
{
- byte *compbuf=my_compress_alloc(packet,len,complen);
+ uchar *compbuf=my_compress_alloc(packet,len,complen);
if (!compbuf)
DBUG_RETURN(*complen ? 0 : 1);
memcpy(packet,compbuf,*len);
- my_free(compbuf,MYF(MY_WME)); }
+ my_free(compbuf,MYF(MY_WME));
+ }
DBUG_RETURN(0);
}
-byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
+uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
{
- byte *compbuf;
+ uchar *compbuf;
+ uLongf tmp_complen;
+ int res;
*complen= *len * 120 / 100 + 12;
- if (!(compbuf= (byte *) my_malloc(*complen,MYF(MY_WME))))
+
+ if (!(compbuf= (uchar *) my_malloc(*complen, MYF(MY_WME))))
return 0; /* Not enough memory */
- if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
- (uLong) *len ) != Z_OK)
+
+ tmp_complen= *complen;
+ res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
+ *complen= tmp_complen;
+
+ if (res != Z_OK)
{
- my_free(compbuf,MYF(MY_WME));
+ my_free(compbuf, MYF(MY_WME));
return 0;
}
+
if (*complen >= *len)
{
*complen= 0;
@@ -67,31 +84,180 @@ byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
DBUG_PRINT("note",("Packet got longer on compression; Not compressed"));
return 0;
}
- swap_variables(ulong, *len, *complen); /* *len is now packet length */
+ /* Store length of compressed packet in *len */
+ swap_variables(size_t, *len, *complen);
return compbuf;
}
-my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
+/*
+ Uncompress packet
+
+ SYNOPSIS
+ my_uncompress()
+ packet Compressed data. This is is replaced with the orignal data.
+ len Length of compressed data
+ complen Length of the packet buffer (must be enough for the original
+ data)
+
+ RETURN
+ 1 error
+ 0 ok. In this case 'complen' contains the updated size of the
+ real data.
+*/
+
+my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
{
+ uLongf tmp_complen;
DBUG_ENTER("my_uncompress");
+
if (*complen) /* If compressed */
{
- byte *compbuf= (byte *) my_malloc(*complen,MYF(MY_WME));
+ uchar *compbuf= (uchar *) my_malloc(*complen,MYF(MY_WME));
int error;
if (!compbuf)
DBUG_RETURN(1); /* Not enough memory */
- if ((error=uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len))
- != Z_OK)
+
+ tmp_complen= *complen;
+ error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
+ (uLong) len);
+ *complen= tmp_complen;
+ if (error != Z_OK)
{ /* Probably wrong packet */
DBUG_PRINT("error",("Can't uncompress packet, error: %d",error));
my_free(compbuf, MYF(MY_WME));
DBUG_RETURN(1);
}
- *len= *complen;
- memcpy(packet, compbuf, *len);
+ memcpy(packet, compbuf, *complen);
my_free(compbuf, MYF(MY_WME));
}
+ else
+ *complen= len;
DBUG_RETURN(0);
}
+
+/*
+ Internal representation of the frm blob is:
+
+ ver 4 bytes
+ orglen 4 bytes
+ complen 4 bytes
+*/
+
+#define BLOB_HEADER 12
+
+
+/*
+ packfrm is a method used to compress the frm file for storage in a
+ handler. This method was developed for the NDB handler and has been moved
+ here to serve also other uses.
+
+ SYNOPSIS
+ packfrm()
+ data Data reference to frm file data.
+ len Length of frm file data
+ out:pack_data Reference to the pointer to the packed frm data
+ out:pack_len Length of packed frm file data
+
+ NOTES
+ data is replaced with compressed content
+
+ RETURN VALUES
+ 0 Success
+ >0 Failure
+*/
+
+int packfrm(uchar *data, size_t len,
+ uchar **pack_data, size_t *pack_len)
+{
+ int error;
+ size_t org_len, comp_len, blob_len;
+ uchar *blob;
+ DBUG_ENTER("packfrm");
+ DBUG_PRINT("enter", ("data: 0x%lx len: %lu", (long) data, (ulong) len));
+
+ error= 1;
+ org_len= len;
+ if (my_compress((uchar*)data, &org_len, &comp_len))
+ goto err;
+
+ DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len, (ulong) comp_len));
+ DBUG_DUMP("compressed", data, org_len);
+
+ error= 2;
+ blob_len= BLOB_HEADER + org_len;
+ if (!(blob= (uchar*) my_malloc(blob_len,MYF(MY_WME))))
+ goto err;
+
+ /* Store compressed blob in machine independent format */
+ int4store(blob, 1);
+ int4store(blob+4, (uint32) len);
+ int4store(blob+8, (uint32) org_len); /* compressed length */
+
+ /* Copy frm data into blob, already in machine independent format */
+ memcpy(blob+BLOB_HEADER, data, org_len);
+
+ *pack_data= blob;
+ *pack_len= blob_len;
+ error= 0;
+
+ DBUG_PRINT("exit", ("pack_data: 0x%lx pack_len: %lu",
+ (long) *pack_data, (ulong) *pack_len));
+err:
+ DBUG_RETURN(error);
+
+}
+
+/*
+ unpackfrm is a method used to decompress the frm file received from a
+ handler. This method was developed for the NDB handler and has been moved
+ here to serve also other uses for other clustered storage engines.
+
+ SYNOPSIS
+ unpackfrm()
+ pack_data Data reference to packed frm file data
+ out:unpack_data Reference to the pointer to the unpacked frm data
+ out:unpack_len Length of unpacked frm file data
+
+ RETURN VALUES¨
+ 0 Success
+ >0 Failure
+*/
+
+int unpackfrm(uchar **unpack_data, size_t *unpack_len,
+ const uchar *pack_data)
+{
+ uchar *data;
+ size_t complen, orglen;
+ ulong ver;
+ DBUG_ENTER("unpackfrm");
+ DBUG_PRINT("enter", ("pack_data: 0x%lx", (long) pack_data));
+
+ ver= uint4korr(pack_data);
+ orglen= uint4korr(pack_data+4);
+ complen= uint4korr(pack_data+8);
+
+ DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu",
+ ver, (ulong) complen, (ulong) orglen));
+ DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen);
+
+ if (ver != 1)
+ DBUG_RETURN(1);
+ if (!(data= my_malloc(max(orglen, complen), MYF(MY_WME))))
+ DBUG_RETURN(2);
+ memcpy(data, pack_data + BLOB_HEADER, complen);
+
+ if (my_uncompress(data, complen, &orglen))
+ {
+ my_free(data, MYF(0));
+ DBUG_RETURN(3);
+ }
+
+ *unpack_data= data;
+ *unpack_len= orglen;
+
+ DBUG_PRINT("exit", ("frmdata: 0x%lx len: %lu", (long) *unpack_data,
+ (ulong) *unpack_len));
+ DBUG_RETURN(0);
+}
#endif /* HAVE_COMPRESS */
diff --git a/mysys/my_conio.c b/mysys/my_conio.c
index def15674f26..b78966446ee 100644
--- a/mysys/my_conio.c
+++ b/mysys/my_conio.c
@@ -29,10 +29,10 @@ static HANDLE my_coninpfh= 0; /* console input */
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
@@ -41,8 +41,8 @@ static HANDLE my_coninpfh= 0; /* console input */
RETURN
0 thread owns mutex
<>0 error
-
*/
+
static
int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time)
{
@@ -69,7 +69,6 @@ int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time)
/*
int my_pthread_auto_mutex_free(HANDLE* ph)
-
NOTES
releases a mutex.
@@ -103,7 +102,7 @@ int my_pthread_auto_mutex_free(HANDLE* ph)
/*
- char* my_cgets(char *string, unsigned long clen, unsigned long* plen)
+ char* my_cgets()
NOTES
Replaces _cgets from libc to support input of more than 255 chars.
@@ -121,10 +120,12 @@ int my_pthread_auto_mutex_free(HANDLE* ph)
NULL Error
*/
-char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen)
+
+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);
@@ -170,8 +171,9 @@ char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen)
clen= min(clen, 65535);
do
{
- clen= min(clen, (unsigned long)csbi.dwSize.X*csbi.dwSize.Y);
- if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, plen, NULL))
+ clen= min(clen, (size_t) csbi.dwSize.X*csbi.dwSize.Y);
+ if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, &plen_res,
+ NULL))
{
result= NULL;
clen>>= 1;
@@ -183,6 +185,7 @@ char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen)
}
}
while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY);
+ *plen= plen_res;
/* We go here on error reading the string (Ctrl-C for example) */
if (!*plen)
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
index ec642b4083c..cd741b1eb52 100644
--- a/mysys/my_copy.c
+++ b/mysys/my_copy.c
@@ -13,7 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
#include <my_dir.h> /* for stat */
#include <m_string.h>
@@ -55,7 +54,7 @@ int my_copy(const char *from, const char *to, myf MyFlags)
my_bool new_file_stat= 0; /* 1 if we could stat "to" */
int create_flag;
File from_file,to_file;
- char buff[IO_SIZE];
+ 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));
@@ -81,10 +80,12 @@ int my_copy(const char *from, const char *to, myf MyFlags)
MyFlags)) < 0)
goto err;
- while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0)
+ 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;
+ }
if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
DBUG_RETURN(-1); /* Error on close */
@@ -94,7 +95,7 @@ int my_copy(const char *from, const char *to, myf MyFlags)
if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
DBUG_RETURN(0); /* File copyed but not stat */
VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
VOID(chown(to, stat_buff.st_uid,stat_buff.st_gid)); /* Copy ownership */
#endif
#if !defined(VMS) && !defined(__ZTC__)
diff --git a/mysys/my_create.c b/mysys/my_create.c
index d612926c1a5..55878318ead 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -13,12 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES
#include "mysys_priv.h"
#include <my_dir.h>
#include "mysys_err.h"
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2)
+#if defined(__WIN__)
#include <share.h>
#endif
@@ -40,21 +39,14 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
FileName, CreateFlags, access_flags, MyFlags));
-#if !defined(NO_OPEN_3) && !defined(__EMX__)
- fd = open((my_string) FileName, access_flags | O_CREAT,
+#if !defined(NO_OPEN_3)
+ fd = open((char *) FileName, access_flags | O_CREAT,
CreateFlags ? CreateFlags : my_umask);
#elif defined(VMS)
- fd = open((my_string) FileName, access_flags | O_CREAT, 0,
+ fd = open((char *) FileName, access_flags | O_CREAT, 0,
"ctx=stm","ctx=bin");
-#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
- if (access_flags & O_SHARE)
- fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
- SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
- else
- fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
- MY_S_IREAD | MY_S_IWRITE);
#elif defined(__WIN__)
- fd= my_sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+ fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY,
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
#else
fd = open(FileName, access_flags);
diff --git a/mysys/my_div.c b/mysys/my_div.c
index 656c6cfde91..d29d3668852 100644
--- a/mysys/my_div.c
+++ b/mysys/my_div.c
@@ -23,7 +23,7 @@
fd File descriptor
*/
-my_string my_filename(File fd)
+char * my_filename(File fd)
{
DBUG_ENTER("my_filename");
if ((uint) fd >= (uint) my_file_limit)
diff --git a/mysys/my_dup.c b/mysys/my_dup.c
index 2c6a42726e4..55f5e0c0099 100644
--- a/mysys/my_dup.c
+++ b/mysys/my_dup.c
@@ -13,12 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES
#include "mysys_priv.h"
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__)
+#if defined(__WIN__)
#include <share.h>
#endif
diff --git a/mysys/my_error.c b/mysys/my_error.c
index 836f851322b..e8fd8b938ee 100644
--- a/mysys/my_error.c
+++ b/mysys/my_error.c
@@ -52,8 +52,10 @@ static struct my_err_head
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};
+
static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs;
+
/*
Error message to user
@@ -75,7 +77,6 @@ int my_error(int nr, myf MyFlags, ...)
va_list args;
char ebuff[ERRMSGSIZE + 20];
DBUG_ENTER("my_error");
-
DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
/* Search for the error messages array, which could contain the message. */
@@ -101,6 +102,7 @@ int my_error(int nr, myf MyFlags, ...)
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
}
+
/*
Error as printf
@@ -189,7 +191,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((gptr)meh_p, MYF(0));
+ my_free((uchar*)meh_p, MYF(0));
return 1;
}
@@ -245,7 +247,19 @@ const char **my_error_unregister(int first, int last)
/* Save the return value and free the header. */
errmsgs= meh_p->meh_errmsgs;
- my_free((gptr) meh_p, MYF(0));
+ my_free((uchar*) meh_p, MYF(0));
return errmsgs;
}
+
+
+void my_error_unregister_all(void)
+{
+ struct my_err_head *list, *next;
+ for (list= my_errmsgs_globerrs.meh_next; list; list= next)
+ {
+ next= list->meh_next;
+ my_free((uchar*) list, MYF(0));
+ }
+ my_errmsgs_list= &my_errmsgs_globerrs;
+}
diff --git a/mysys/my_file.c b/mysys/my_file.c
index c97a512f8a1..44bacf55307 100644
--- a/mysys/my_file.c
+++ b/mysys/my_file.c
@@ -32,7 +32,7 @@
May be more or less than max_file_limit!
*/
-#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) && !defined(HAVE_mit_thread)
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
#ifndef RLIM_INFINITY
#define RLIM_INFINITY ((uint) 0xffffffff)
@@ -71,25 +71,6 @@ static uint set_max_open_files(uint max_file_limit)
DBUG_RETURN(max_file_limit);
}
-#elif defined (OS2)
-
-static uint set_max_open_files(uint max_file_limit)
-{
- LONG cbReqCount;
- ULONG cbCurMaxFH0;
- APIRET ulrc;
- DBUG_ENTER("set_max_open_files");
-
- /* get current limit */
- cbReqCount = 0;
- DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH0);
-
- /* set new limit */
- if ((cbReqCount = max_file_limit - cbCurMaxFH0) > 0)
- ulrc = DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH);
- DBUG_RETURN(cbCurMaxFH0);
-}
-
#else
static int set_max_open_files(uint max_file_limit)
{
@@ -125,7 +106,10 @@ uint my_set_max_open_files(uint files)
DBUG_RETURN(MY_NFILE);
/* Copy any initialized files */
- memcpy((char*) tmp, (char*) my_file_info, sizeof(*tmp) * my_file_limit);
+ memcpy((char*) tmp, (char*) my_file_info,
+ sizeof(*tmp) * min(my_file_limit, files));
+ bzero((char*) (tmp + my_file_limit),
+ max((int) (files- my_file_limit), 0)*sizeof(*tmp));
my_free_open_file_info(); /* Free if already allocated */
my_file_info= tmp;
my_file_limit= files;
@@ -139,8 +123,12 @@ void my_free_open_file_info()
DBUG_ENTER("my_free_file_info");
if (my_file_info != my_file_info_default)
{
+ /* 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_file_info= my_file_info_default;
+ my_file_limit= MY_NFILE;
}
DBUG_VOID_RETURN;
}
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index b56be263ba4..44156da6ae3 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -18,7 +18,7 @@
#include <errno.h>
#include "mysys_err.h"
-static void make_ftype(my_string to,int flag);
+static void make_ftype(char * to,int flag);
/*
Open a file as stream
@@ -76,6 +76,7 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
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);
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
@@ -192,7 +193,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
a+ == O_RDWR|O_APPEND|O_CREAT
*/
-static void make_ftype(register my_string to, register int flag)
+static void make_ftype(register char * to, register int flag)
{
/* check some possible invalid combinations */
DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND));
diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c
index ea30509ca8c..f5fe862937c 100644
--- a/mysys/my_fstream.c
+++ b/mysys/my_fstream.c
@@ -27,24 +27,31 @@
#define fseek(A,B,C) fseeko((A),(B),(C))
#endif
- /* Read a chunk of bytes from a file */
- /* Returns (uint) -1 if error as my_read() */
-
-uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
- /* File descriptor */
- /* Buffer must be at least count bytes */
- /* Max number of bytes returnd */
- /* Flags on what to do on error */
+/*
+ Read a chunk of bytes from a FILE
+
+ SYNOPSIS
+ my_fread()
+ stream File descriptor
+ Buffer Buffer to read to
+ Count Number of bytes to read
+ MyFlags Flags on what to do on error
+
+ RETURN
+ (size_t) -1 Error
+ # Number of bytes read
+ */
+
+size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
{
- uint readbytes;
+ size_t readbytes;
DBUG_ENTER("my_fread");
DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d",
- (long) stream, (long) Buffer, Count, MyFlags));
+ (long) stream, (long) Buffer, (uint) Count, MyFlags));
- if ((readbytes = (uint) fread(Buffer,sizeof(char),(size_t) Count,stream))
- != Count)
+ if ((readbytes= fread(Buffer, sizeof(char), Count, stream)) != Count)
{
- DBUG_PRINT("error",("Read only %d bytes",readbytes));
+ DBUG_PRINT("error",("Read only %d bytes", (int) readbytes));
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
if (ferror(stream))
@@ -57,7 +64,7 @@ uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
}
my_errno=errno ? errno : -1;
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
- DBUG_RETURN((uint) -1); /* Return with error */
+ DBUG_RETURN((size_t) -1); /* Return with error */
}
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Read ok */
@@ -66,40 +73,48 @@ uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
/*
-** Write a chunk of bytes to a stream
-** Returns (uint) -1 if error as my_write()
-** Does retries if interrupted
+ Write a chunk of bytes to a stream
+
+ my_fwrite()
+ stream File descriptor
+ Buffer Buffer to write from
+ Count Number of bytes to write
+ MyFlags Flags on what to do on error
+
+ RETURN
+ (size_t) -1 Error
+ # Number of bytes written
*/
-uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
+size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
{
- uint writenbytes=0;
- off_t seekptr;
+ size_t writtenbytes =0;
+ my_off_t seekptr;
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
uint errors;
#endif
DBUG_ENTER("my_fwrite");
DBUG_PRINT("my",("stream: 0x%lx Buffer: 0x%lx Count: %u MyFlags: %d",
- (long) stream, (long) Buffer, Count, MyFlags));
+ (long) stream, (long) Buffer, (uint) Count, MyFlags));
#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
errors=0;
#endif
- seekptr=ftell(stream);
+ seekptr= ftell(stream);
for (;;)
{
- uint writen;
- if ((writen = (uint) fwrite((char*) Buffer,sizeof(char),
- (size_t) Count, stream)) != Count)
+ size_t written;
+ if ((written = (size_t) fwrite((char*) Buffer,sizeof(char),
+ Count, stream)) != Count)
{
- DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+ DBUG_PRINT("error",("Write only %d bytes", (int) writtenbytes));
my_errno=errno;
- if (writen != (uint) -1)
+ if (written != (size_t) -1)
{
- seekptr+=writen;
- Buffer+=writen;
- writenbytes+=writen;
- Count-=writen;
+ seekptr+=written;
+ Buffer+=written;
+ writtenbytes+=written;
+ Count-=written;
}
#ifdef EINTR
if (errno == EINTR)
@@ -131,21 +146,21 @@ uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
my_filename(fileno(stream)),errno);
}
- writenbytes=(uint) -1; /* Return that we got error */
+ writtenbytes= (size_t) -1; /* Return that we got error */
break;
}
}
if (MyFlags & (MY_NABP | MY_FNABP))
- writenbytes=0; /* Everything OK */
+ writtenbytes= 0; /* Everything OK */
else
- writenbytes+=writen;
+ writtenbytes+= written;
break;
}
- DBUG_RETURN(writenbytes);
+ DBUG_RETURN(writtenbytes);
} /* my_fwrite */
- /* Seek to position in file */
- /* ARGSUSED */
+
+/* Seek to position in file */
my_off_t my_fseek(FILE *stream, my_off_t pos, int whence,
myf MyFlags __attribute__((unused)))
@@ -158,8 +173,7 @@ my_off_t my_fseek(FILE *stream, my_off_t pos, int whence,
} /* my_seek */
- /* Tell current position of file */
- /* ARGSUSED */
+/* Tell current position of file */
my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
{
diff --git a/mysys/my_gethostbyname.c b/mysys/my_gethostbyname.c
index 434a00bab11..067fdfee9db 100644
--- a/mysys/my_gethostbyname.c
+++ b/mysys/my_gethostbyname.c
@@ -18,7 +18,7 @@
/* Thread safe version of gethostbyname_r() */
#include "mysys_priv.h"
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <netdb.h>
#endif
#include <my_net.h>
diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c
index 01abc02058b..845b5aa4152 100644
--- a/mysys/my_gethwaddr.c
+++ b/mysys/my_gethwaddr.c
@@ -19,7 +19,7 @@
#include "mysys_priv.h"
#include <m_string.h>
-#ifndef MAIN
+#if !defined(__FreeBSD__) || defined(__linux__)
static my_bool memcpy_and_test(uchar *to, uchar *from, uint len)
{
uint i, res=1;
diff --git a/mysys/my_getncpus.c b/mysys/my_getncpus.c
new file mode 100644
index 00000000000..82e87dee2e4
--- /dev/null
+++ b/mysys/my_getncpus.c
@@ -0,0 +1,39 @@
+/* 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 */
+
+/* get the number of (online) CPUs */
+
+#include "mysys_priv.h"
+#include <unistd.h>
+
+static int ncpus=0;
+
+#ifdef _SC_NPROCESSORS_ONLN
+int my_getncpus()
+{
+ if (!ncpus)
+ ncpus= sysconf(_SC_NPROCESSORS_ONLN);
+ return ncpus;
+}
+
+#else
+/* unknown */
+int my_getncpus()
+{
+ return 2;
+}
+
+#endif
+
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 623c48b2e55..3a5b130e067 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -32,8 +32,9 @@ my_bool getopt_compare_strings(const char *s,
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 double getopt_double(char *arg, const struct my_option *optp, int *err);
static void init_variables(const struct my_option *options);
-static int setval(const struct my_option *opts, gptr *value, char *argument,
+static int setval(const struct my_option *opts, uchar* *value, char *argument,
my_bool set_maximum_value);
static char *check_struct_option(char *cur_arg, char *key_name);
@@ -58,6 +59,13 @@ char *disabled_my_option= (char*) "0";
my_bool my_getopt_print_errors= 1;
+/*
+ This is a flag that can be set in client programs. 1 means that
+ my_getopt will skip over options it does not know how to handle.
+*/
+
+my_bool my_getopt_skip_unknown= 0;
+
static void default_reporter(enum loglevel level,
const char *format, ...)
{
@@ -82,9 +90,9 @@ static void default_reporter(enum loglevel level,
one. Call function 'get_one_option()' once for each option.
*/
-static gptr* (*getopt_get_addr)(const char *, uint, const struct my_option *);
+static uchar** (*getopt_get_addr)(const char *, uint, const struct my_option *);
-void my_getopt_register_get_addr(gptr* (*func_addr)(const char *, uint,
+void my_getopt_register_get_addr(uchar** (*func_addr)(const char *, uint,
const struct my_option *))
{
getopt_get_addr= func_addr;
@@ -94,22 +102,26 @@ 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, i;
+ uint 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, *prev_found,
*opt_str, key_name[FN_REFLEN];
const struct my_option *optp;
- gptr *value;
- int error;
+ uchar* *value;
+ int error, i;
LINT_INIT(opt_found);
+ /* handle_options() assumes arg0 (program name) always exists */
+ DBUG_ASSERT(argc && *argc >= 1);
+ DBUG_ASSERT(argv && *argv);
(*argc)--; /* Skip the program name */
(*argv)++; /* --- || ---- */
init_variables(longopts);
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
{
+ char **first= pos;
char *cur_arg= *pos;
if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
{
@@ -216,12 +228,11 @@ int handle_options(int *argc, char ***argv,
/*
We were called with a special prefix, we can reuse opt_found
*/
- opt_str+= (special_opt_prefix_lengths[i] + 1);
+ opt_str+= special_opt_prefix_lengths[i] + 1;
+ length-= special_opt_prefix_lengths[i] + 1;
if (i == OPT_LOOSE)
option_is_loose= 1;
- if ((opt_found= findopt(opt_str, length -
- (special_opt_prefix_lengths[i] + 1),
- &optp, &prev_found)))
+ if ((opt_found= findopt(opt_str, length, &optp, &prev_found)))
{
if (opt_found > 1)
{
@@ -245,7 +256,7 @@ int handle_options(int *argc, char ***argv,
break;
case OPT_ENABLE:
optend= (optend && *optend == '0' && !(*(optend + 1))) ?
- disabled_my_option : (char*) "1";
+ disabled_my_option : (char*) "1";
break;
case OPT_MAXIMUM:
set_maximum_value= 1;
@@ -254,11 +265,25 @@ int handle_options(int *argc, char ***argv,
}
break; /* break from the inner loop, main loop continues */
}
+ i= -1; /* restart the loop */
}
}
}
if (!opt_found)
{
+ 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
+ */
+ do {
+ (*argv)[argvpos++]= *first++;
+ } while (first <= pos);
+ continue;
+ }
if (must_be_var)
{
if (my_getopt_print_errors)
@@ -491,7 +516,7 @@ invalid value '%s'\n",
}
get_one_option(optp->id, optp, argument);
- (*argc)--; /* option handled (short or long), decrease argument count */
+ (*argc)--; /* option handled (short or long), decrease argument count */
}
else /* non-option found */
(*argv)[argvpos++]= cur_arg;
@@ -556,14 +581,14 @@ static char *check_struct_option(char *cur_arg, char *key_name)
Will set the option value to given value
*/
-static int setval(const struct my_option *opts, gptr *value, char *argument,
+static int setval(const struct my_option *opts, uchar* *value, char *argument,
my_bool set_maximum_value)
{
int err= 0;
if (value && argument)
{
- gptr *result_pos= ((set_maximum_value) ?
+ uchar* *result_pos= ((set_maximum_value) ?
opts->u_max_value : value);
if (!result_pos)
@@ -587,6 +612,9 @@ static int setval(const struct my_option *opts, gptr *value, char *argument,
case GET_ULL:
*((ulonglong*) result_pos)= getopt_ull(argument, opts, &err);
break;
+ case GET_DOUBLE:
+ *((double*) result_pos)= getopt_double(argument, opts, &err);
+ break;
case GET_STR:
*((char**) result_pos)= argument;
break;
@@ -596,6 +624,15 @@ static int setval(const struct my_option *opts, gptr *value, char *argument,
if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME))))
return EXIT_OUT_OF_MEMORY;
break;
+ case GET_ENUM:
+ if (((*(int*)result_pos)= find_type(argument, opts->typelib, 2) - 1) < 0)
+ return EXIT_ARGUMENT_INVALID;
+ break;
+ case GET_SET:
+ *((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err);
+ if (err)
+ return EXIT_ARGUMENT_INVALID;
+ break;
default: /* dummy default to avoid compiler warnings */
break;
}
@@ -687,7 +724,7 @@ my_bool getopt_compare_strings(register const char *s, register const char *t,
be k|K for kilo, m|M for mega or g|G for giga.
*/
-static longlong eval_num_suffix (char *argument, int *error, char *option_name)
+static longlong eval_num_suffix(char *argument, int *error, char *option_name)
{
char *endchar;
longlong num;
@@ -769,6 +806,37 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp)
/*
+ Get double value withing ranges
+
+ Evaluates and returns the value that user gave as an argument to a variable.
+
+ RETURN
+ decimal value of arg
+
+ In case of an error, prints an error message and sets *err to
+ EXIT_ARGUMENT_INVALID. Otherwise err is not touched
+*/
+
+static double getopt_double(char *arg, const struct my_option *optp, int *err)
+{
+ double num;
+ int error;
+ char *end= arg + 1000; /* Big enough as *arg is \0 terminated */
+ 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);
+ *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);
+}
+
+/*
Init one value to it's default values
SYNOPSIS
@@ -777,9 +845,10 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp)
value Pointer to variable
*/
-static void init_one_value(const struct my_option *option, gptr *variable,
+static void init_one_value(const struct my_option *option, uchar* *variable,
longlong value)
{
+ DBUG_ENTER("init_one_value");
switch ((option->var_type & GET_TYPE_MASK)) {
case GET_BOOL:
*((my_bool*) variable)= (my_bool) value;
@@ -788,6 +857,7 @@ static void init_one_value(const struct my_option *option, gptr *variable,
*((int*) variable)= (int) value;
break;
case GET_UINT:
+ case GET_ENUM:
*((uint*) variable)= (uint) value;
break;
case GET_LONG:
@@ -800,11 +870,39 @@ static void init_one_value(const struct my_option *option, gptr *variable,
*((longlong*) variable)= (longlong) value;
break;
case GET_ULL:
+ case GET_SET:
*((ulonglong*) variable)= (ulonglong) value;
break;
+ case GET_DOUBLE:
+ *((double*) variable)= (double) value;
+ break;
+ case GET_STR:
+ /*
+ Do not clear variable value if it has no default value.
+ The default value may already be set.
+ NOTE: To avoid compiler warnings, we first cast longlong to intptr,
+ so that the value has the same size as a pointer.
+ */
+ if ((char*) (intptr) value)
+ *((char**) variable)= (char*) (intptr) value;
+ break;
+ case GET_STR_ALLOC:
+ /*
+ Do not clear variable value if it has no default value.
+ The default value may already be set.
+ NOTE: To avoid compiler warnings, we first cast longlong to intptr,
+ so that the value has the same size as a pointer.
+ */
+ if ((char*) (intptr) value)
+ {
+ my_free((*(char**) variable), MYF(MY_ALLOW_ZERO_PTR));
+ *((char**) variable)= my_strdup((char*) (intptr) value, MYF(MY_WME));
+ }
+ break;
default: /* dummy default to avoid compiler warnings */
break;
}
+ DBUG_VOID_RETURN;
}
@@ -823,9 +921,11 @@ static void init_one_value(const struct my_option *option, gptr *variable,
static void init_variables(const struct my_option *options)
{
+ DBUG_ENTER("init_variables");
for (; options->name; options++)
{
- gptr *variable;
+ uchar* *variable;
+ DBUG_PRINT("options", ("name: '%s'", options->name));
/*
We must set u_max_value first as for some variables
options->u_max_value == options->value and in this case we want to
@@ -839,6 +939,7 @@ static void init_variables(const struct my_option *options)
(variable= (*getopt_get_addr)("", 0, options)))
init_one_value(options, variable, options->def_value);
}
+ DBUG_VOID_RETURN;
}
@@ -928,7 +1029,8 @@ void my_print_help(const struct my_option *options)
void my_print_variables(const struct my_option *options)
{
- uint name_space= 34, length;
+ uint name_space= 34, length, nr;
+ ulonglong bit, llvalue;
char buff[255];
const struct my_option *optp;
@@ -937,15 +1039,30 @@ void my_print_variables(const struct my_option *options)
printf("--------------------------------- -----------------------------\n");
for (optp= options; optp->id; optp++)
{
- gptr *value= (optp->var_type & GET_ASK_ADDR ?
+ uchar* *value= (optp->var_type & GET_ASK_ADDR ?
(*getopt_get_addr)("", 0, optp) : optp->value);
if (value)
{
- printf("%s", optp->name);
- length= (uint) strlen(optp->name);
+ printf("%s ", optp->name);
+ length= (uint) strlen(optp->name)+1;
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)");
+ else
+ for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1)
+ {
+ if (!(bit & llvalue))
+ continue;
+ llvalue&= ~bit;
+ printf( llvalue ? "%s," : "%s\n", get_type(optp->typelib, nr));
+ }
+ break;
+ case GET_ENUM:
+ printf("%s\n", get_type(optp->typelib, *(uint*) value));
+ break;
case GET_STR:
case GET_STR_ALLOC: /* fall through */
printf("%s\n", *((char**) value) ? *((char**) value) :
@@ -961,7 +1078,7 @@ void my_print_variables(const struct my_option *options)
printf("%d\n", *((uint*) value));
break;
case GET_LONG:
- printf("%lu\n", *((long*) value));
+ printf("%ld\n", *((long*) value));
break;
case GET_ULONG:
printf("%lu\n", *((ulong*) value));
@@ -973,6 +1090,9 @@ void my_print_variables(const struct my_option *options)
longlong2str(*((ulonglong*) value), buff, 10);
printf("%s\n", buff);
break;
+ case GET_DOUBLE:
+ printf("%g\n", *(double*) value);
+ break;
default:
printf("(Disabled)\n");
break;
diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c
index 2fd7eed7778..43bb6c08af9 100644
--- a/mysys/my_getsystime.c
+++ b/mysys/my_getsystime.c
@@ -17,11 +17,13 @@
/* thus to get the current time we should use the system function
with the highest possible resolution */
+#include "mysys_priv.h"
+#include "my_static.h"
+
#ifdef __NETWARE__
#include <nks/time.h>
#endif
-#include "mysys_priv.h"
ulonglong my_getsystime()
{
#ifdef HAVE_CLOCK_GETTIME
@@ -29,28 +31,15 @@ ulonglong my_getsystime()
clock_gettime(CLOCK_REALTIME, &tp);
return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100;
#elif defined(__WIN__)
-#define OFFSET_TO_EPOC ((__int64) 134774 * 24 * 60 * 60 * 1000 * 1000 * 10)
- static __int64 offset=0, freq;
LARGE_INTEGER t_cnt;
- if (!offset)
+ if (query_performance_frequency)
{
- /* strictly speaking there should be a mutex to protect
- initialization section. But my_getsystime() is called from
- UUID() code, and UUID() calls are serialized with a mutex anyway
- */
- LARGE_INTEGER li;
- FILETIME ft;
- GetSystemTimeAsFileTime(&ft);
- li.LowPart=ft.dwLowDateTime;
- li.HighPart=ft.dwHighDateTime;
- offset=li.QuadPart-OFFSET_TO_EPOC;
- QueryPerformanceFrequency(&li);
- freq=li.QuadPart;
QueryPerformanceCounter(&t_cnt);
- offset-=t_cnt.QuadPart/freq*10000000+t_cnt.QuadPart%freq*10000000/freq;
+ return (t_cnt.QuadPart / query_performance_frequency * 10000000+
+ t_cnt.QuadPart % query_performance_frequency * 10000000/
+ query_performance_frequency+query_performance_offset);
}
- QueryPerformanceCounter(&t_cnt);
- return t_cnt.QuadPart/freq*10000000+t_cnt.QuadPart%freq*10000000/freq+offset;
+ return 0;
#elif defined(__NETWARE__)
NXTime_t tm;
NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm);
@@ -62,3 +51,176 @@ ulonglong my_getsystime()
return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10;
#endif
}
+
+
+/*
+ Return current time
+
+ SYNOPSIS
+ my_time()
+ flags If MY_WME is set, write error if time call fails
+
+*/
+
+time_t my_time(myf flags __attribute__((unused)))
+{
+ time_t t;
+#ifdef HAVE_GETHRTIME
+ (void) my_micro_time_and_time(&t);
+ return t;
+#else
+ /* The following loop is here beacuse time() may fail on some systems */
+ while ((t= time(0)) == (time_t) -1)
+ {
+ if (flags & MY_WME)
+ fprintf(stderr, "%s: Warning: time() call failed\n", my_progname);
+ }
+ return t;
+#endif
+}
+
+
+/*
+ Return time in micro seconds
+
+ SYNOPSIS
+ my_micro_time()
+
+ NOTES
+ This function is to be used to measure performance in micro seconds.
+ As it's not defined whats the start time for the clock, this function
+ us only useful to measure time between two moments.
+
+ For windows platforms we need the frequency value of the CUP. This is
+ initalized in my_init.c through QueryPerformanceFrequency().
+
+ If Windows platform doesn't support QueryPerformanceFrequency() we will
+ obtain the time via GetClockCount, which only supports milliseconds.
+
+ RETURN
+ Value in microseconds from some undefined point in time
+*/
+
+ulonglong my_micro_time()
+{
+ ulonglong newtime;
+#if defined(__WIN__)
+ if (query_performance_frequency)
+ {
+ QueryPerformanceCounter((LARGE_INTEGER*) &newtime);
+ newtime/= (query_performance_frequency * 1000000);
+ }
+ else
+ newtime= (GetTickCount() * 1000); /* GetTickCount only returns milliseconds */
+ return newtime;
+#elif defined(HAVE_GETHRTIME)
+ return gethrtime()/1000;
+#else
+ struct timeval t;
+ /* The following loop is here because gettimeofday may fail on some systems */
+ while (gettimeofday(&t, NULL) != 0)
+ {}
+ newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
+ return newtime;
+#endif /* defined(__WIN__) */
+}
+
+
+/*
+ Return time in seconds and timer in microseconds (not different start!)
+
+ SYNOPSIS
+ my_micro_time_and_time()
+ time_arg Will be set to seconds since epoch (00:00:00 UTC, January 1,
+ 1970)
+
+ NOTES
+ This function is to be useful when we need both the time and microtime.
+ For example in MySQL this is used to get the query time start of a query and
+ to measure the time of a query (for the slow query log)
+
+ IMPLEMENTATION
+ Value of time is as in time() call.
+ Value of microtime is same as my_micro_time(), which may be totally unrealated
+ to time()
+
+ RETURN
+ Value in microseconds from some undefined point in time
+*/
+
+#define DELTA_FOR_SECONDS LL(500000000) /* Half a second */
+
+ulonglong my_micro_time_and_time(time_t *time_arg)
+{
+ ulonglong newtime;
+#if defined(__WIN__)
+ if (query_performance_frequency)
+ {
+ QueryPerformanceCounter((LARGE_INTEGER*) &newtime);
+ newtime/= (query_performance_frequency * 1000000);
+ }
+ else
+ newtime= (GetTickCount() * 1000); /* GetTickCount only returns milliseconds */
+ (void) time(time_arg);
+ return newtime;
+#elif defined(HAVE_GETHRTIME)
+ /*
+ Solaris has a very slow time() call. We optimize this by using the very fast
+ gethrtime() call and only calling time() every 1/2 second
+ */
+ static hrtime_t prev_gethrtime= 0;
+ static time_t cur_time= 0;
+ hrtime_t cur_gethrtime;
+
+ pthread_mutex_lock(&THR_LOCK_time);
+ cur_gethrtime= gethrtime();
+ if ((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);
+ return cur_gethrtime/1000;
+#else
+ struct timeval t;
+ /* The following loop is here because gettimeofday may fail on some systems */
+ while (gettimeofday(&t, NULL) != 0)
+ {}
+ *time_arg= t.tv_sec;
+ newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
+ return newtime;
+#endif /* defined(__WIN__) */
+}
+
+
+/*
+ Returns current time
+
+ SYNOPSIS
+ my_time_possible_from_micro()
+ microtime Value from very recent my_micro_time()
+
+ NOTES
+ This function returns the current time. The microtime argument is only used
+ if my_micro_time() uses a function that can safely be converted to the current
+ time.
+
+ RETURN
+ current time
+*/
+
+time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused)))
+{
+#if defined(__WIN__)
+ time_t t;
+ while ((t= time(0)) == (time_t) -1)
+ {}
+ return t;
+#elif defined(HAVE_GETHRTIME)
+ return my_time(0); /* Cached time */
+#else
+ return (time_t) (microtime / 1000000);
+#endif /* defined(__WIN__) */
+}
+
diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c
index 3870a5d61b0..cbfebcf2374 100644
--- a/mysys/my_getwd.c
+++ b/mysys/my_getwd.c
@@ -21,36 +21,38 @@
#ifdef HAVE_GETWD
#include <sys/param.h>
#endif
-#if defined(MSDOS) || defined(__WIN__)
+#if defined(__WIN__)
#include <m_ctype.h>
#include <dos.h>
#include <direct.h>
#endif
-#if defined(OS2)
-#include <direct.h>
-#endif
-#ifdef __EMX__
-/* chdir2 support also drive change */
-#define chdir _chdir2
-#endif
+/* Gets current working directory in buff.
- /* Gets current working directory in buff. Directory is allways ended
- with FN_LIBCHAR */
- /* One must pass a buffer to my_getwd. One can allways use
- curr_dir[] */
+ SYNPOSIS
+ my_getwd()
+ buf Buffer to store result. Can be curr_dir[].
+ size Size of buffer
+ MyFlags Flags
+
+ NOTES
+ Directory is allways ended with FN_LIBCHAR
+
+ RESULT
+ 0 ok
+ # error
+*/
-int my_getwd(my_string buf, uint size, myf MyFlags)
+int my_getwd(char * buf, size_t size, myf MyFlags)
{
- my_string pos;
+ char * pos;
DBUG_ENTER("my_getwd");
- DBUG_PRINT("my",("buf: 0x%lx size: %d MyFlags %d", (long) buf,size,MyFlags));
+ DBUG_PRINT("my",("buf: 0x%lx size: %u MyFlags %d",
+ (long) buf, (uint) size, MyFlags));
-#if ! defined(MSDOS)
if (curr_dir[0]) /* Current pos is saved here */
VOID(strmake(buf,&curr_dir[0],size-1));
else
-#endif
{
#if defined(HAVE_GETCWD)
if (!getcwd(buf,size-2) && MyFlags & MY_WME)
@@ -81,61 +83,26 @@ int my_getwd(my_string buf, uint size, myf MyFlags)
pos[0]= FN_LIBCHAR;
pos[1]=0;
}
- (void) strmake(&curr_dir[0],buf,(size_s) (FN_REFLEN-1));
+ (void) strmake(&curr_dir[0],buf, (size_t) (FN_REFLEN-1));
}
DBUG_RETURN(0);
} /* my_getwd */
- /* Set new working directory */
+/* Set new working directory */
int my_setwd(const char *dir, myf MyFlags)
{
int res;
- size_s length;
- my_string start,pos;
-#if defined(VMS) || defined(MSDOS) || defined(OS2)
+ 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=(my_string) dir;
-#if defined(MSDOS) || defined(OS2) /* OS2/MSDOS chdir can't change drive */
-#if !defined(_DDL) && !defined(WIN32)
- if ((pos=(char*) strchr(dir,FN_DEVCHAR)) != 0)
- {
- uint drive,drives;
-
- pos++; /* Skip FN_DEVCHAR */
- drive=(uint) (my_toupper(&my_charset_latin1,dir[0])-'A'+1);
- drives= (uint) -1;
- if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
- {
-#ifdef OS2
- _chdrive(drive);
- drives = _getdrive();
-#else
- _dos_setdrive(drive,&drives);
- _dos_getdrive(&drives);
-#endif
- }
- if (drive != drives)
- {
- *pos='\0'; /* Dir is now only drive */
- my_errno=errno;
- my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
- DBUG_RETURN(-1);
- }
- dir=pos; /* drive changed, change now path */
- }
-#endif
- if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
- {
- strmov(buff,dir)[-1]=0; /* Remove last '/' */
- dir=buff;
- }
-#endif /* MSDOS*/
+ start=(char *) dir;
if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
dir=FN_ROOTDIR;
#ifdef VMS
@@ -160,7 +127,7 @@ int my_setwd(const char *dir, myf MyFlags)
{
if (test_if_hard_path(start))
{ /* Hard pathname */
- pos=strmake(&curr_dir[0],start,(size_s) FN_REFLEN-1);
+ pos= strmake(&curr_dir[0],start,(size_t) FN_REFLEN-1);
if (pos[-1] != FN_LIBCHAR)
{
length=(uint) (pos-(char*) curr_dir);
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 32d3f07fd31..257edb351b4 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -69,7 +69,7 @@ static ulong atoi_octal(const char *str)
my_bool my_init(void)
{
- my_string str;
+ char * str;
if (my_init_done)
return 0;
my_init_done=1;
@@ -86,13 +86,10 @@ my_bool my_init(void)
#endif
if (my_thread_global_init())
return 1;
-#if !defined( __WIN__) && !defined(OS2) && !defined(__NETWARE__)
+#if !defined( __WIN__) && !defined(__NETWARE__)
sigfillset(&my_signals); /* signals blocked by mf_brkhant */
#endif
#endif /* THREAD */
-#ifdef UNIXWARE_7
- (void) isatty(0); /* Go around connect() bug in UW7 */
-#endif
{
DBUG_ENTER("my_init");
DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown"));
@@ -133,14 +130,18 @@ void my_end(int infoflag)
*/
FILE *info_file= DBUG_FILE;
my_bool print_info= (info_file != stderr);
- DBUG_ENTER("my_end");
+ /*
+ We do not use DBUG_ENTER here, as after cleanup DBUG is no longer
+ operational, so we cannot use DBUG_RETURN.
+ */
+ DBUG_PRINT("info",("Shutting down: infoflag: %d print_info: %d",
+ infoflag, print_info));
if (!info_file)
{
info_file= stderr;
print_info= 0;
}
- DBUG_PRINT("info",("Shutting down: print_info: %d", print_info));
if ((infoflag & MY_CHECK_ERROR) || print_info)
{ /* Test if some file is left open */
@@ -149,9 +150,11 @@ void my_end(int infoflag)
sprintf(errbuff[0],EE(EE_OPEN_WARNING),my_file_opened,my_stream_opened);
(void) my_message_no_curses(EE_OPEN_WARNING,errbuff[0],ME_BELL);
DBUG_PRINT("error",("%s",errbuff[0]));
+ my_print_open_files();
}
}
free_charsets();
+ my_error_unregister_all();
my_once_free();
if ((infoflag & MY_GIVE_INFO) || print_info)
@@ -179,11 +182,11 @@ 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(MSDOS) || defined(__NETWARE__) ) && !defined(__WIN__)
+#if defined(__NETWARE__) && !defined(__WIN__)
fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
#endif
#if defined(SAFEMALLOC)
- TERMINATE(stderr); /* Give statistic on screen */
+ TERMINATE(stderr, (infoflag & MY_GIVE_INFO) != 0);
#elif defined(__WIN__) && defined(_MSC_VER)
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
@@ -195,6 +198,10 @@ 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))
{
@@ -208,7 +215,8 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
Check on destroying of mutexes. A few may be left that will get cleaned
up by C++ destructors
*/
- safe_mutex_end(infoflag & MY_GIVE_INFO ? stderr : (FILE *) 0);
+ safe_mutex_end((infoflag & (MY_GIVE_INFO | MY_CHECK_ERROR)) ? stderr :
+ (FILE *) 0);
#endif /* defined(SAFE_MUTEX) */
#endif /* THREAD */
@@ -247,14 +255,16 @@ void setEnvString(char *ret, const char *name, const char *value)
}
/*
- my_paramter_handler
- Invalid paramter handler we will use instead of the one "baked" into the CRT
- for MSC v8. This one just prints out what invalid parameter was encountered.
- By providing this routine, routines like lseek will return -1 when we expect them
- to instead of crash.
+ my_parameter_handler
+
+ Invalid parameter handler we will use instead of the one "baked"
+ into the CRT for MSC v8. This one just prints out what invalid
+ parameter was encountered. By providing this routine, routines like
+ lseek will return -1 when we expect them to instead of crash.
*/
-void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
- const wchar_t * file, unsigned int line,
+
+void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
+ const wchar_t * file, unsigned int line,
uintptr_t pReserved)
{
DBUG_PRINT("my",("Expression: %s function: %s file: %s, line: %d",
@@ -366,6 +376,28 @@ static void my_win_init(void)
/* chiude la chiave */
RegCloseKey(hSoftMysql) ;
+
+ /* 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))
+ 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);
+ }
+ }
DBUG_VOID_RETURN ;
}
diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c
index 9714c582acb..a20111396cb 100644
--- a/mysys/my_largepage.c
+++ b/mysys/my_largepage.c
@@ -26,8 +26,8 @@
#endif
static uint my_get_large_page_size_int(void);
-static gptr my_large_malloc_int(uint size, myf my_flags);
-static my_bool my_large_free_int(gptr ptr, myf my_flags);
+static uchar* my_large_malloc_int(size_t size, myf my_flags);
+static my_bool my_large_free_int(uchar* ptr, myf my_flags);
/* Gets the size of large pages from the OS */
@@ -48,9 +48,9 @@ uint my_get_large_page_size(void)
my_malloc_lock() in case of failure
*/
-gptr my_large_malloc(uint size, myf my_flags)
+uchar* my_large_malloc(size_t size, myf my_flags)
{
- gptr ptr;
+ uchar* ptr;
DBUG_ENTER("my_large_malloc");
if (my_use_large_pages && my_large_page_size)
@@ -70,7 +70,7 @@ gptr my_large_malloc(uint size, myf my_flags)
to my_free_lock() in case of failure
*/
-void my_large_free(gptr ptr, myf my_flags __attribute__((unused)))
+void my_large_free(uchar* ptr, myf my_flags __attribute__((unused)))
{
DBUG_ENTER("my_large_free");
@@ -113,29 +113,29 @@ finish:
#if HAVE_DECL_SHM_HUGETLB
/* Linux-specific large pages allocator */
-gptr my_large_malloc_int(uint size, myf my_flags)
+uchar* my_large_malloc_int(size_t size, myf my_flags)
{
int shmid;
- gptr ptr;
+ uchar* ptr;
struct shmid_ds buf;
DBUG_ENTER("my_large_malloc_int");
/* Align block size to my_large_page_size */
size = ((size - 1) & ~(my_large_page_size - 1)) + my_large_page_size;
- shmid = shmget(IPC_PRIVATE, (size_t)size, SHM_HUGETLB | SHM_R | SHM_W);
+ 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 %d bytes from HugeTLB memory."
- " errno %d\n", size, errno);
+ "Warning: Failed to allocate %lu bytesx from HugeTLB memory."
+ " errno %d\n", (ulong) size, errno);
DBUG_RETURN(NULL);
}
- ptr = shmat(shmid, NULL, 0);
- if (ptr == (void *)-1)
+ ptr = (uchar*) shmat(shmid, NULL, 0);
+ if (ptr == (uchar *) -1)
{
if (my_flags& MY_WME)
fprintf(stderr, "Warning: Failed to attach shared memory segment,"
@@ -156,7 +156,7 @@ gptr my_large_malloc_int(uint size, myf my_flags)
/* Linux-specific large pages deallocator */
-my_bool my_large_free_int(byte *ptr, myf my_flags __attribute__((unused)))
+my_bool my_large_free_int(uchar *ptr, myf my_flags __attribute__((unused)))
{
DBUG_ENTER("my_large_free_int");
DBUG_RETURN(shmdt(ptr) == 0);
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
index 61de4ff9065..c10b2e391b4 100644
--- a/mysys/my_lib.c
+++ b/mysys/my_lib.c
@@ -14,9 +14,8 @@
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 */
+/* Convert MSDOS-TIME to standar time_t (still needed?) */
-#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
#include <m_string.h>
#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
@@ -25,9 +24,7 @@
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
-#ifndef OS2
# define dirent direct
-#endif
# define NAMLEN(dirent) (dirent)->d_namlen
# if defined(HAVE_SYS_NDIR_H)
# include <sys/ndir.h>
@@ -38,7 +35,7 @@
# if defined(HAVE_NDIR_H)
# include <ndir.h>
# endif
-# if defined(MSDOS) || defined(__WIN__)
+# if defined(__WIN__)
# include <dos.h>
# ifdef __BORLANDC__
# include <dir.h>
@@ -51,10 +48,6 @@
#include <descrip.h>
#endif
-#ifdef OS2
-#include "my_os2dirsrch.h"
-#endif
-
#if defined(THREAD) && defined(HAVE_READDIR_R)
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
#else
@@ -85,7 +78,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((gptr) buffer,MYF(0));
+ my_free((uchar*) buffer,MYF(0));
}
DBUG_VOID_RETURN;
} /* my_dirend */
@@ -99,7 +92,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
} /* comp_names */
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
MY_DIR *my_dir(const char *path, myf MyFlags)
{
@@ -121,7 +114,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
pthread_mutex_lock(&THR_LOCK_open);
#endif
- dirp = opendir(directory_file_name(tmp_path,(my_string) path));
+ dirp = opendir(directory_file_name(tmp_path,(char *) path));
#if defined(__amiga__)
if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
goto error;
@@ -139,7 +132,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((gptr) buffer,MYF(0));
+ my_free((uchar*) buffer,MYF(0));
goto error;
}
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
@@ -175,7 +168,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
else
finfo.mystat= NULL;
- if (push_dynamic(dir_entries_storage, (gptr)&finfo))
+ if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
goto error;
}
@@ -215,13 +208,13 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
* Returns pointer to dst;
*/
-my_string directory_file_name (my_string dst, const char *src)
+char * directory_file_name (char * dst, const char *src)
{
#ifndef VMS
/* Process as Unix format: just remove test the final slash. */
- my_string end;
+ char * end;
if (src[0] == 0)
src= (char*) "."; /* Use empty as current */
@@ -237,7 +230,7 @@ my_string directory_file_name (my_string dst, const char *src)
long slen;
long rlen;
- my_string ptr, rptr;
+ char * ptr, rptr;
char bracket;
struct FAB fab = cc$rms_fab;
struct NAM nam = cc$rms_nam;
@@ -352,7 +345,7 @@ my_string directory_file_name (my_string dst, const char *src)
#endif /* VMS */
} /* directory_file_name */
-#elif defined(WIN32)
+#else
/*
*****************************************************************************
@@ -391,7 +384,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
*tmp_file++= '.'; /* From current dev-dir */
if (tmp_file[-1] != FN_LIBCHAR)
*tmp_file++ =FN_LIBCHAR;
- tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[0]='*'; /* Windows needs this !??? */
tmp_file[1]='.';
tmp_file[2]='*';
tmp_file[3]='\0';
@@ -408,7 +401,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((gptr) buffer,MYF(0));
+ my_free((uchar*) buffer,MYF(0));
goto error;
}
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
@@ -482,7 +475,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags)
else
finfo.mystat= NULL;
- if (push_dynamic(dir_entries_storage, (gptr)&finfo))
+ if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
goto error;
}
#ifdef __BORLANDC__
@@ -514,109 +507,7 @@ error:
DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
-#else /* MSDOS and not WIN32 */
-
-
-/******************************************************************************
-** At MSDOS you always get stat of files, but time is in packed MSDOS-format
-******************************************************************************/
-
-MY_DIR *my_dir(const char* path, myf MyFlags)
-{
- char *buffer;
- MY_DIR *result= 0;
- FILEINFO finfo;
- DYNAMIC_ARRAY *dir_entries_storage;
- MEM_ROOT *names_storage;
- struct find_t find;
- ushort mode;
- char tmp_path[FN_REFLEN],*tmp_file,attrib;
- DBUG_ENTER("my_dir");
- DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
-
- /* Put LIB-CHAR as last path-character if not there */
-
- tmp_file=tmp_path;
- if (!*path)
- *tmp_file++ ='.'; /* From current dir */
- tmp_file= strmov(tmp_file,path);
- if (tmp_file[-1] == FN_DEVCHAR)
- *tmp_file++= '.'; /* From current dev-dir */
- if (tmp_file[-1] != FN_LIBCHAR)
- *tmp_file++ =FN_LIBCHAR;
- tmp_file[0]='*'; /* MSDOS needs this !??? */
- tmp_file[1]='.';
- tmp_file[2]='*';
- tmp_file[3]='\0';
-
- if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
- goto error;
-
- if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
- ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
- sizeof(MEM_ROOT), MyFlags)))
- goto error;
-
- dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
- names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
- ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
-
- if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
- ENTRIES_START_SIZE, ENTRIES_INCREMENT))
- {
- my_free((gptr) buffer,MYF(0));
- goto error;
- }
- init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
-
- /* MY_DIR structure is allocated and completly initialized at this point */
- result= (MY_DIR*)buffer;
-
- do
- {
- if (!(finfo.name= strdup_root(names_storage, find.name)))
- goto error;
-
- if (MyFlags & MY_WANT_STAT)
- {
- if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
- sizeof(MY_STAT))))
- goto error;
-
- bzero(finfo.mystat, sizeof(MY_STAT));
- finfo.mystat->st_size= find.size;
- mode= MY_S_IREAD; attrib= find.attrib;
- if (!(attrib & _A_RDONLY))
- mode|= MY_S_IWRITE;
- if (attrib & _A_SUBDIR)
- mode|= MY_S_IFDIR;
- finfo.mystat->st_mode= mode;
- finfo.mystat->st_mtime= ((uint32) find.wr_date << 16) + find.wr_time;
- }
- else
- finfo.mystat= NULL;
-
- if (push_dynamic(dir_entries_storage, (gptr)&finfo))
- goto error;
-
- } while (_dos_findnext(&find) == 0);
-
- result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
- result->number_off_files= dir_entries_storage->elements;
-
- if (!(MyFlags & MY_DONT_SORT))
- qsort((void *) result->dir_entry, result->number_off_files,
- sizeof(FILEINFO), (qsort_cmp) comp_names);
- DBUG_RETURN(result);
-
-error:
- my_dirend(result);
- if (MyFlags & MY_FAE+MY_WME)
- my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
- DBUG_RETURN((MY_DIR *) NULL);
-} /* my_dir */
-
-#endif /* WIN32 && MSDOS */
+#endif /* __WIN__ */
/****************************************************************************
** File status
@@ -642,13 +533,13 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
if ((m_used= (stat_area == NULL)))
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
goto error;
- if (! stat((my_string) path, (struct stat *) stat_area) )
+ if (! stat((char *) path, (struct stat *) stat_area) )
DBUG_RETURN(stat_area);
DBUG_PRINT("error",("Got errno: %d from stat", errno));
my_errno= errno;
if (m_used) /* Free if new area */
- my_free((gptr) stat_area,MYF(0));
+ my_free((uchar*) stat_area,MYF(0));
error:
if (my_flags & (MY_FAE+MY_WME))
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
index a07f0c072a0..c0522ee849d 100644
--- a/mysys/my_lock.c
+++ b/mysys/my_lock.c
@@ -25,11 +25,6 @@
#ifdef __WIN__
#include <sys/locking.h>
#endif
-#ifdef __EMX__
-#define INCL_BASE
-#define INCL_NOPMAPI
-#include <os2emx.h>
-#endif
#ifdef __NETWARE__
#include <nks/fsio.h>
#endif
@@ -102,11 +97,6 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
DBUG_RETURN(0);
}
}
-#elif defined(__EMX__) || defined(OS2)
-
- if (!_lock64( fd, locktype, start, length, MyFlags))
- DBUG_RETURN(0);
-
#elif defined(HAVE_LOCKING)
/* Windows */
{
diff --git a/mysys/my_lockmem.c b/mysys/my_lockmem.c
index a58a5a340b1..b96331cd3cf 100644
--- a/mysys/my_lockmem.c
+++ b/mysys/my_lockmem.c
@@ -25,17 +25,17 @@
struct st_mem_list
{
LIST list;
- byte *page;
+ uchar *page;
uint size;
};
LIST *mem_list;
-byte *my_malloc_lock(uint size,myf MyFlags)
+uchar *my_malloc_lock(uint size,myf MyFlags)
{
int success;
uint pagesize=sysconf(_SC_PAGESIZE);
- byte *ptr;
+ uchar *ptr;
struct st_mem_list *element;
DBUG_ENTER("my_malloc_lock");
@@ -46,7 +46,7 @@ byte *my_malloc_lock(uint size,myf MyFlags)
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
DBUG_RETURN(0);
}
- success = mlock((byte*) ptr,size);
+ success = mlock((uchar*) ptr,size);
if (success != 0 && geteuid() == 0)
{
DBUG_PRINT("warning",("Failed to lock memory. errno %d\n",
@@ -59,11 +59,11 @@ byte *my_malloc_lock(uint size,myf MyFlags)
/* Add block in a list for munlock */
if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags)))
{
- VOID(munlock((byte*) ptr,size));
+ VOID(munlock((uchar*) ptr,size));
free(ptr);
DBUG_RETURN(0);
}
- element->list.data=(byte*) element;
+ element->list.data=(uchar*) element;
element->page=ptr;
element->size=size;
pthread_mutex_lock(&THR_LOCK_malloc);
@@ -74,7 +74,7 @@ byte *my_malloc_lock(uint size,myf MyFlags)
}
-void my_free_lock(byte *ptr,myf Myflags __attribute__((unused)))
+void my_free_lock(uchar *ptr,myf Myflags __attribute__((unused)))
{
LIST *list;
struct st_mem_list *element=0;
@@ -85,14 +85,14 @@ void my_free_lock(byte *ptr,myf Myflags __attribute__((unused)))
element=(struct st_mem_list*) list->data;
if (ptr == element->page)
{ /* Found locked mem */
- VOID(munlock((byte*) ptr,element->size));
+ VOID(munlock((uchar*) ptr,element->size));
mem_list=list_delete(mem_list,list);
break;
}
}
pthread_mutex_unlock(&THR_LOCK_malloc);
if (element)
- my_free((gptr) element,MYF(0));
+ my_free((uchar*) element,MYF(0));
free(ptr); /* Free even if not locked */
}
diff --git a/mysys/my_lread.c b/mysys/my_lread.c
deleted file mode 100644
index 1399b197119..00000000000
--- a/mysys/my_lread.c
+++ /dev/null
@@ -1,54 +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 */
-
-#include "mysys_priv.h"
-#include "mysys_err.h"
-
- /* Read a chunk of bytes from a file */
-
-uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags)
- /* File descriptor */
- /* Buffer must be at least count bytes */
- /* Max number of bytes returnd */
- /* Flags on what to do on error */
-{
- uint32 readbytes;
- DBUG_ENTER("my_lread");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
- Filedes, (long) Buffer, (ulong) Count, MyFlags));
-
- DBUG_PRINT("error", ("Deprecated my_lread() function should not be used."));
-
- /* Temp hack to get count to int32 while read wants int */
- if ((readbytes = (uint32) read(Filedes, Buffer, (uint) Count)) != Count)
- {
- my_errno=errno;
- if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
- {
- if (readbytes == MY_FILE_ERROR)
- my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
- my_filename(Filedes),errno);
- else
- if (MyFlags & (MY_NABP | MY_FNABP))
- my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
- my_filename(Filedes),errno);
- }
- if (readbytes == MY_FILE_ERROR || MyFlags & (MY_NABP | MY_FNABP))
- DBUG_RETURN((uint32) -1); /* Return med felkod */
- }
- if (MyFlags & (MY_NABP | MY_FNABP))
- DBUG_RETURN(0); /* Ok vid l{sning */
- DBUG_RETURN(readbytes);
-} /* my_lread */
diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c
deleted file mode 100644
index d26825397e3..00000000000
--- a/mysys/my_lwrite.c
+++ /dev/null
@@ -1,47 +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 */
-
-#include "mysys_priv.h"
-#include "mysys_err.h"
-
- /* Write a chunk of bytes to a file */
-
-uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags)
-{
- uint32 writenbytes;
- DBUG_ENTER("my_lwrite");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
- Filedes, (long) Buffer, (ulong) Count, MyFlags));
-
- DBUG_PRINT("error", ("Deprecated my_lwrite() function should not be used."));
-
- /* Temp hack to get count to int32 while write wants int */
- if ((writenbytes = (uint32) write(Filedes, Buffer, (uint) Count)) != Count)
- {
- my_errno=errno;
- if (writenbytes == (uint32) -1 || 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),errno);
- }
- DBUG_RETURN((uint32) -1); /* Return med felkod */
- }
- }
- if (MyFlags & (MY_NABP | MY_FNABP))
- DBUG_RETURN(0); /* Ok vid l{sning */
- DBUG_RETURN(writenbytes);
-} /* my_lwrite */
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
index 38d0263b495..12793ad451b 100644
--- a/mysys/my_malloc.c
+++ b/mysys/my_malloc.c
@@ -23,11 +23,11 @@
/* My memory allocator */
-gptr my_malloc(unsigned int size, myf my_flags)
+void *my_malloc(size_t size, myf my_flags)
{
- gptr point;
+ void* point;
DBUG_ENTER("my_malloc");
- DBUG_PRINT("my",("size: %u my_flags: %d",size, my_flags));
+ DBUG_PRINT("my",("size: %lu my_flags: %d", (ulong) size, my_flags));
if (!size)
size=1; /* Safety */
@@ -44,14 +44,14 @@ gptr my_malloc(unsigned int size, myf my_flags)
else if (my_flags & MY_ZEROFILL)
bzero(point,size);
DBUG_PRINT("exit",("ptr: 0x%lx", (long) point));
- DBUG_RETURN(point);
+ DBUG_RETURN((void*) point);
} /* my_malloc */
/* Free memory allocated with my_malloc */
/*ARGSUSED*/
-void my_no_flags_free(gptr ptr)
+void my_no_flags_free(void* ptr)
{
DBUG_ENTER("my_free");
DBUG_PRINT("my",("ptr: 0x%lx", (long) ptr));
@@ -63,32 +63,32 @@ void my_no_flags_free(gptr ptr)
/* malloc and copy */
-gptr my_memdup(const byte *from, uint length, myf my_flags)
+void* my_memdup(const void *from, size_t length, myf my_flags)
{
- gptr ptr;
- if ((ptr=my_malloc(length,my_flags)) != 0)
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ void *ptr;
+ if ((ptr= my_malloc(length,my_flags)) != 0)
+ memcpy(ptr, from, length);
return(ptr);
}
char *my_strdup(const char *from, myf my_flags)
{
- gptr ptr;
- uint length=(uint) strlen(from)+1;
- if ((ptr=my_malloc(length,my_flags)) != 0)
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
- return((my_string) ptr);
+ 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);
}
-char *my_strdup_with_length(const char *from, uint length, myf my_flags)
+char *my_strndup(const char *from, size_t length, myf my_flags)
{
- gptr ptr;
- if ((ptr=my_malloc(length+1,my_flags)) != 0)
+ char *ptr;
+ if ((ptr= (char*) my_malloc(length+1,my_flags)) != 0)
{
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
- ((char*) ptr)[length]=0;
+ memcpy((uchar*) ptr, (uchar*) from, length);
+ ptr[length]=0;
}
return((char*) ptr);
}
diff --git a/mysys/my_memmem.c b/mysys/my_memmem.c
index 9230337409d..c000f14bc66 100644
--- a/mysys/my_memmem.c
+++ b/mysys/my_memmem.c
@@ -22,8 +22,9 @@
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 void *needle, size_t needlelen)
{
const unsigned char *cursor;
const unsigned char *last_possible_needle_location =
diff --git a/mysys/my_mkdir.c b/mysys/my_mkdir.c
index 25176e4b823..676c6c1cd51 100644
--- a/mysys/my_mkdir.c
+++ b/mysys/my_mkdir.c
@@ -26,7 +26,7 @@ int my_mkdir(const char *dir, int Flags, myf MyFlags)
DBUG_ENTER("my_dir");
DBUG_PRINT("enter",("dir: %s",dir));
-#if defined(__WIN__) || defined(OS2)
+#if defined(__WIN__)
if (mkdir((char*) dir))
#else
if (mkdir((char*) dir, Flags & my_umask_dir))
diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c
index 147bdfdcbf2..023a06fd896 100644
--- a/mysys/my_mmap.c
+++ b/mysys/my_mmap.c
@@ -35,22 +35,19 @@ static SECURITY_ATTRIBUTES mmap_security_attributes=
void *my_mmap(void *addr, size_t len, int prot,
int flags, int fd, my_off_t offset)
{
- DWORD flProtect=0;
HANDLE hFileMap;
LPVOID ptr;
HANDLE hFile= (HANDLE)_get_osfhandle(fd);
if (hFile == INVALID_HANDLE_VALUE)
return MAP_FAILED;
- flProtect|=SEC_COMMIT;
-
hFileMap=CreateFileMapping(hFile, &mmap_security_attributes,
PAGE_READWRITE, 0, (DWORD) len, NULL);
if (hFileMap == 0)
return MAP_FAILED;
ptr=MapViewOfFile(hFileMap,
- flags & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ,
+ prot & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ,
(DWORD)(offset >> 32), (DWORD)offset, len);
/*
diff --git a/mysys/my_net.c b/mysys/my_net.c
index 136d987f500..81d977210f8 100644
--- a/mysys/my_net.c
+++ b/mysys/my_net.c
@@ -19,7 +19,7 @@
#include <m_string.h>
/* for thread safe my_inet_ntoa */
-#if !defined(MSDOS) && !defined(__WIN__)
+#if !defined(__WIN__)
#include <netdb.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -30,7 +30,7 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#endif /* !defined(MSDOS) && !defined(__WIN__) */
+#endif /* !defined(__WIN__) */
void my_inet_ntoa(struct in_addr in, char *buf)
{
diff --git a/mysys/my_once.c b/mysys/my_once.c
index d83eba95b9d..b6f6656fce2 100644
--- a/mysys/my_once.c
+++ b/mysys/my_once.c
@@ -36,10 +36,10 @@
No DBUG_ENTER... here to get smaller dbug-startup
*/
-gptr my_once_alloc(unsigned int Size, myf MyFlags)
+void* my_once_alloc(size_t Size, myf MyFlags)
{
- uint get_size,max_left;
- gptr point;
+ size_t get_size, max_left;
+ uchar* point;
reg1 USED_MEM *next;
reg2 USED_MEM **prev;
@@ -63,34 +63,36 @@ gptr my_once_alloc(unsigned int Size, myf MyFlags)
my_errno=errno;
if (MyFlags & (MY_FAE+MY_WME))
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
- return((gptr) 0);
+ return((uchar*) 0);
}
- DBUG_PRINT("test",("my_once_malloc %u byte malloced",get_size));
+ DBUG_PRINT("test",("my_once_malloc %lu byte malloced", (ulong) get_size));
next->next= 0;
next->size= get_size;
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
*prev=next;
}
- point= (gptr) ((char*) next+ (next->size-next->left));
+ point= (uchar*) ((char*) next+ (next->size-next->left));
next->left-= Size;
- return(point);
+ if (MyFlags & MY_ZEROFILL)
+ bzero(point, Size);
+ return((void*) point);
} /* my_once_alloc */
char *my_once_strdup(const char *src,myf myflags)
{
- uint len= (uint) strlen(src)+1;
- char *dst=my_once_alloc(len, myflags);
+ size_t len= strlen(src)+1;
+ uchar *dst= my_once_alloc(len, myflags);
if (dst)
memcpy(dst, src, len);
- return dst;
+ return (char*) dst;
}
-char *my_once_memdup(const char *src, uint len, myf myflags)
+void *my_once_memdup(const void *src, size_t len, myf myflags)
{
- char *dst=my_once_alloc(len, myflags);
+ uchar *dst= my_once_alloc(len, myflags);
if (dst)
memcpy(dst, src, len);
return dst;
@@ -112,7 +114,7 @@ void my_once_free(void)
for (next=my_once_root_block ; next ; )
{
old=next; next= next->next ;
- free((gptr) old);
+ free((uchar*) old);
}
my_once_root_block=0;
diff --git a/mysys/my_open.c b/mysys/my_open.c
index 9e1da1d3f07..938dbc5dde2 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -13,12 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES
#include "mysys_priv.h"
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
-#if defined(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2)
+#if defined(__WIN__)
#include <share.h>
#endif
@@ -44,7 +43,7 @@ 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(MSDOS) || defined(__WIN__) || defined(__EMX__) || defined(OS2)
+#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)
@@ -57,20 +56,20 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
}
#ifndef __WIN__
if (Flags & O_SHARE)
- fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
+ fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
MY_S_IREAD | MY_S_IWRITE);
else
- fd = open((my_string) FileName, Flags | O_BINARY,
+ fd = open((char *) FileName, Flags | O_BINARY,
MY_S_IREAD | MY_S_IWRITE);
#else
- fd= my_sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
+ fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
MY_S_IREAD | MY_S_IWRITE);
#endif
#elif !defined(NO_OPEN_3)
fd = open(FileName, Flags, my_umask); /* Normal unix */
#else
- fd = open((my_string) FileName, Flags);
+ fd = open((char *) FileName, Flags);
#endif
DBUG_RETURN(my_register_filename(fd, FileName, FILE_BY_OPEN,
EE_FILENOTFOUND, MyFlags));
@@ -152,6 +151,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
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);
@@ -167,9 +167,17 @@ File my_register_filename(File fd, const char *FileName, enum file_type
else
my_errno=errno;
DBUG_PRINT("error",("Got error %d on open",my_errno));
- if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
- my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) {
+ if (my_errno == EMFILE) {
+ DBUG_PRINT("error",("print err: %d",EE_OUT_OF_FILERESOURCES));
+ my_error(EE_OUT_OF_FILERESOURCES, MYF(ME_BELL+ME_WAITTANG),
FileName, my_errno);
+ } else {
+ DBUG_PRINT("error",("print err: %d",error_message_number));
+ my_error(error_message_number, MYF(ME_BELL+ME_WAITTANG),
+ FileName, my_errno);
+ }
+ }
return(fd);
}
@@ -355,3 +363,24 @@ File my_sopen(const char *path, int oflag, int shflag, int pmode)
return fh; /* return handle */
}
#endif /* __WIN__ */
+
+
+#ifdef EXTRA_DEBUG
+
+void my_print_open_files(void)
+{
+ if (my_file_opened | my_stream_opened)
+ {
+ uint i;
+ for (i= 0 ; i < my_file_limit ; i++)
+ {
+ if (my_file_info[i].type != UNOPEN)
+ {
+ fprintf(stderr, EE(EE_FILE_NOT_CLOSED), my_file_info[i].name, i);
+ fputc('\n', stderr);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/mysys/my_os2cond.c b/mysys/my_os2cond.c
deleted file mode 100644
index f0cf91404d2..00000000000
--- a/mysys/my_os2cond.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-/*****************************************************************************
-** The following is a simple implementation of posix conditions
-*****************************************************************************/
-
-#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
-#include "mysys_priv.h"
-#if defined(THREAD) && defined(OS2)
-#include <m_string.h>
-#include <process.h>
-#include <sys/timeb.h>
-
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
-{
- cond->waiting= 0;
- /* Warp3 FP29 or Warp4 FP4 or better required */
- if (DosCreateEventSem(NULL, &cond->semaphore, 0x0800, 0))
- return ENOMEM;
- return 0;
-}
-
-int pthread_cond_destroy(pthread_cond_t *cond)
-{
- for (;;)
- {
- APIRET rc;
- if ((rc= DosCloseEventSem(cond->semaphore)) != 301)
- return rc ? EINVAL : 0;
- DosPostEventSem(cond->semaphore);
- }
-}
-
-
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
- int rval= 0;
- cond->waiting++;
- if (mutex)
- pthread_mutex_unlock(mutex);
- if (DosWaitEventSem(cond->semaphore, SEM_INDEFINITE_WAIT))
- rval= EINVAL;
- if (mutex)
- pthread_mutex_lock(mutex);
- cond->waiting--;
- return rval;
-}
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
- struct timespec *abstime)
-{
- struct timeb curtime;
- int result;
- long timeout;
- int rval= 0;
-
- _ftime(&curtime);
- timeout= ((long) (abstime->ts_sec - curtime.time) * 1000L +
- (long) ((abstime->ts_nsec / 1000) - curtime.millitm) / 1000L);
- if (timeout < 0) /* Some safety */
- timeout= 0L;
-
- cond->waiting++;
-
- if (mutex)
- pthread_mutex_unlock(mutex);
- if (DosWaitEventSem(cond->semaphore, timeout) != 0)
- rval= ETIMEDOUT;
- if (mutex)
- pthread_mutex_lock(mutex);
-
- cond->waiting--;
-
- return rval;
-}
-
-
-int pthread_cond_signal(pthread_cond_t *cond)
-{
- /* Bring the next thread off the condition queue: */
- DosPostEventSem(cond->semaphore);
- return 0;
-}
-
-
-int pthread_cond_broadcast(pthread_cond_t *cond)
-{
- int i;
- /* Enter a loop to bring all threads off the condition queue */
- for (i= cond->waiting; i--;)
- DosPostEventSem(cond->semaphore);
- return 0;
-}
-
-
-int pthread_attr_init(pthread_attr_t *connect_att)
-{
- connect_att->dwStackSize= 0;
- connect_att->dwCreatingFlag= 0;
- connect_att->priority= 0;
- return 0;
-}
-
-int pthread_attr_setstacksize(pthread_attr_t *connect_att, DWORD stack)
-{
- connect_att->dwStackSize= 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((gptr) connect_att, sizeof(*connect_att));
- return 0;
-}
-
-/****************************************************************************
-** Fix localtime_r() to be a bit safer
-****************************************************************************/
-
-struct tm *localtime_r(const time_t *timep, struct tm *tmp)
-{
- if (*timep == (time_t) - 1) /* This will crash win32 */
- {
- bzero(tmp, sizeof(*tmp));
- }
- else
- {
- struct tm *res= localtime(timep);
- if (!res) /* Wrong date */
- {
- bzero(tmp, sizeof(*tmp)); /* Keep things safe */
- return 0;
- }
- *tmp= *res;
- }
- return tmp;
-}
-#endif /* __WIN__ */
diff --git a/mysys/my_os2dirsrch.c b/mysys/my_os2dirsrch.c
deleted file mode 100644
index 27e774c8e04..00000000000
--- a/mysys/my_os2dirsrch.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000-2003 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-
-/* Win32 directory search emulation */
-
-#if defined(OS2)
-
-long _findfirst( char* path, struct _finddata_t* dos_file)
-{
- HDIR hdir = HDIR_CREATE;
- APIRET rc;
- FILEFINDBUF3 buf3;
- ULONG entries = 1;
-
-#ifdef _DEBUG
- printf( "_findfirst path %s\n", path);
-#endif
-
- memset( &buf3, 0, sizeof( buf3));
- rc = DosFindFirst(
- path, /* The ASCIIZ path name of the file or subdirectory to be found. */
- &hdir, /* The handle associated with this DosFindFirst request. */
- FILE_NORMAL | FILE_DIRECTORY, /* Attribute value that determines the file objects to be searched for. */
- &buf3, /* Result buffer. */
- sizeof( buf3), /* The length, in bytes, of pfindbuf. */
- &entries, /* Pointer to the number of entries: */
- FIL_STANDARD); /* The level of file information required. */
-
-#ifdef _DEBUG
- printf( "_findfirst rc=%d hdir=%d entries=%d->%s\n", rc, hdir, entries,
- buf3.achName);
-#endif
-
- if (rc /* && entries == 0 */)
- return -1;
-
- if (dos_file)
- {
- memset( dos_file, 0, sizeof( struct _finddata_t));
- strcpy( dos_file->name, buf3.achName);
- dos_file->size = buf3.cbFile;
- dos_file->attrib = buf3.attrFile;
- }
- return (ULONG) hdir;
-}
-
-
-long _findnext( long hdir, struct _finddata_t* dos_file)
-{
- APIRET rc;
- FILEFINDBUF3 buf3;
- ULONG entries = 1;
-
- memset( &buf3, 0, sizeof( buf3));
- rc = DosFindNext(hdir,
- &buf3, /* Result buffer. */
- sizeof( buf3), /* Length, in bytes, of pfindbuf. */
- &entries); /* Pointer to the number of entries */
-
-#ifdef _DEBUG
- printf( "_findnext rc=%d hdir=%d entries=%d->%s\n", rc, hdir, entries,
- buf3.achName);
-#endif
-
- if (rc /* && entries == 0 */)
- return -1;
-
- if (dos_file)
- {
- memset( dos_file, 0, sizeof( struct _finddata_t));
- strcpy( dos_file->name, buf3.achName);
- dos_file->size = buf3.cbFile;
- dos_file->attrib = buf3.attrFile;
- }
- return 0;
-}
-
-void _findclose( long hdir)
-{
- APIRET rc;
-
- rc = DosFindClose( hdir);
-#ifdef _DEBUG
- printf( "_findclose rc=%d hdir=%d\n", rc, hdir);
-#endif
-}
-
-DIR* opendir(char* path)
-{
- DIR* dir = (DIR*) calloc(1, sizeof( DIR));
- char buffer[260];
- APIRET rc;
- ULONG entries = 1;
-
- strmov(strmov(buffer, path), "*.*");
-
-#ifdef _DEBUG
- printf( "_findfirst path %s\n", buffer);
-#endif
-
- dir->hdir = HDIR_CREATE;
- memset( &dir->buf3, 0, sizeof( dir->buf3));
- rc = DosFindFirst(
- buffer, /* Address of the ASCIIZ path name of the file or subdirectory to be found. */
- &dir->hdir, /* Address of the handle associated with this DosFindFirst request. */
- FILE_NORMAL | FILE_DIRECTORY, /* Attribute value that determines the file objects to be searched for. */
- &dir->buf3, /* Result buffer. */
- sizeof( dir->buf3), /* The length, in bytes, of pfindbuf. */
- &entries, /* Pointer to the number of entries: */
- FIL_STANDARD); /* The level of file information required. */
-
-#ifdef _DEBUG
- printf( "opendir rc=%d hdir=%d entries=%d->%s\n", rc, dir->hdir, entries, dir->buf3.achName);
-#endif
-
- if (rc /* && entries == 0 */)
- return NULL;
-
- return dir;
-}
-
-
-struct dirent* readdir( DIR* dir)
-{
- APIRET rc;
- ULONG entries = 1;
-
- if (!dir->buf3.achName[0]) /* file not found on previous query */
- return NULL;
-
- /* copy last file name */
- strcpy( dir->ent.d_name, dir->buf3.achName);
-
- /* query next file */
- memset( &dir->buf3, 0, sizeof( dir->buf3));
- rc= DosFindNext(
- dir->hdir,
- &dir->buf3, /* Result buffer. */
- sizeof(dir->buf3), /* Length, in bytes, of pfindbuf. */
- &entries); /* Pointer to the number of entries */
-
-#ifdef _DEBUG
- printf( "_findnext rc=%d hdir=%d entries=%d->%s\n", rc, dir->hdir, entries,
- dir->buf3.achName);
-#endif
-
- if (rc /* && entries == 0 */)
- *dir->buf3.achName= 0; /* reset name for next query */
-
- return &dir->ent;
-}
-
-
-int closedir (DIR *dir)
-{
- APIRET rc;
-
- rc = DosFindClose( dir->hdir);
-#ifdef _DEBUG
- printf( "_findclose rc=%d hdir=%d\n", rc, dir->hdir);
-#endif
- free(dir);
- return 0;
-}
-
-#endif /* OS2 */
diff --git a/mysys/my_os2dirsrch.h b/mysys/my_os2dirsrch.h
deleted file mode 100644
index e3af6740769..00000000000
--- a/mysys/my_os2dirsrch.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-/* Win32 directory search emulation */
-
-#ifndef __MY_OS2DIRSRCH2_H__
-#define __MY_OS2DIRSRCH2_H__
-
-#ifdef __cplusplus_00
-extern "C" {
-#endif
-
-struct _finddata_t
-{
- unsigned attrib;
-#ifdef NOT_USED
- unsigned long time_create; /* -1 for FAT file systems */
- unsigned long time_access; /* -1 for FAT file systems */
- unsigned long time_write;
-#endif
- unsigned long size;
- char name[260];
-#ifdef NOT_USED
- uint16 wr_date;
- uint16 wr_time;
-#endif
-};
-
-
-struct dirent
-{
-#ifdef NOT_USED
- unsigned attrib;
- unsigned long time_create; /* -1 for FAT file systems */
- unsigned long time_access; /* -1 for FAT file systems */
- unsigned long time_write;
- unsigned long size;
-#endif
- char d_name[260];
-#ifdef NOT_USED
- uint16 wr_date;
- uint16 wr_time;
-#endif
-};
-
-struct DIR
-{
- HDIR hdir;
- FILEFINDBUF3 buf3;
- struct dirent ent;
-};
-
-DIR *opendir ( char *);
-struct dirent *readdir (DIR *);
-int closedir (DIR *);
-
-#ifdef NOT_USED
-#define _A_NORMAL FILE_NORMAL
-#define _A_SUBDIR FILE_DIRECTORY
-#define _A_RDONLY FILE_READONLY
-
-long _findfirst( char*, struct _finddata_t*);
-long _findnext( long, struct _finddata_t*);
-void _findclose( long);
-#endif
-
-#ifdef __cplusplus_00
-}
-#endif
-
-#endif /* __MY_OS2DIRSRCH2_H__ */
diff --git a/mysys/my_os2dlfcn.c b/mysys/my_os2dlfcn.c
deleted file mode 100644
index 74be940d0d4..00000000000
--- a/mysys/my_os2dlfcn.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-/*
- * dlfcn::Unix dynamic loading for OS/2
- *
- * Compatibility layer for dynamic loading.
- * Only minimal implementation
- *
-*/
-
-#define RTLD_LAZY 0
-#define RTLD_NOW 0
-
-void* dlopen( char* path, int flag);
-char* dlerror( void);
-void* dlsym( void* hmod, char* fn);
-void dlclose( void* hmod);
-
-char fail[ 256];
-
-void* dlopen( char* path, int flag)
-{
- APIRET rc;
- HMODULE hmod;
-
- rc = DosLoadModule( fail, sizeof( fail), path, &hmod);
- if (rc)
- return NULL;
-
- return (void*) hmod;
-}
-
-char* dlerror( void)
-{
- return fail;
-}
-
-void* dlsym( void* hmod, char* fn)
-{
- APIRET rc;
- PFN addr;
-
- rc = DosQueryProcAddr( (HMODULE) hmod, 0l, fn, &addr);
- if (rc)
- return NULL;
-
- return (void*) addr;
-}
-
-void dlclose( void* hmod)
-{
- APIRET rc;
-
- rc = DosFreeModule( (HMODULE) hmod);
-
-}
diff --git a/mysys/my_os2dlfcn.h0 b/mysys/my_os2dlfcn.h0
deleted file mode 100644
index ec05eebc47b..00000000000
--- a/mysys/my_os2dlfcn.h0
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-/*
- * dlfcn::Unix dynamic loading for OS/2
- *
- * Compatibility layer for dynamic loading.
- * Only minimal implementation
- *
-*/
-
-#ifndef __DLFCN_H__
-#define __DLFCN_H__
-
-#define RTLD_LAZY 0
-#define RTLD_NOW 0
-
-void* dlopen( char* path, int flag);
-char* dlerror( void);
-void* dlsym( void* hmod, char* fn);
-void dlclose( void* hmod);
-
-#endif
diff --git a/mysys/my_os2file64.c b/mysys/my_os2file64.c
deleted file mode 100644
index 52156903b80..00000000000
--- a/mysys/my_os2file64.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-void _OS2errno( APIRET rc);
-longlong _lseek64( int fd, longlong offset, int seektype);
-int _lock64( int fd, int locktype, my_off_t start,
- my_off_t length, myf MyFlags);
-int _sopen64( const char *name, int oflag, int shflag, int mask);
-
-/*
- This class is used to define a global c++ variable, that
- is initialized before main() gets called.
-*/
-
-class File64bit
-{
- public:
- File64bit(); /* default constructor */
-} initFile64bit;
-
-static APIRET (* APIENTRY _DosOpenL)(PCSZ pszFileName,
- PHFILE phf,
- PULONG pulAction,
- LONGLONG cbFile,
- ULONG ulAttribute,
- ULONG fsOpenFlags,
- ULONG fsOpenMode,
- PEAOP2 peaop2);
-static APIRET (* APIENTRY _DosSetFilePtrL)(HFILE hFile,
- LONGLONG ib,
- ULONG method,
- PLONGLONG ibActual);
-static APIRET (* APIENTRY _DosSetFileLocksL)(HFILE hFile,
- PFILELOCKL pflUnlock,
- PFILELOCKL pflLock,
- ULONG timeout,
- ULONG flags);
-
-#define EIO EINVAL
-#define ESPIPE EBADSEEK
-
-
-static unsigned char const errno_tab[] =
-{
- 0 , EINVAL, ENOENT, ENOENT, EMFILE, /* 0..4 */
- EACCES, EBADF, EIO, ENOMEM, EIO, /* 5..9 */
- EINVAL, ENOEXEC,EINVAL, EINVAL, EINVAL, /* 10..14 */
- ENOENT, EBUSY, EXDEV, ENOENT, EROFS, /* 15..19 */
- EIO, EIO, EIO, EIO, EIO, /* 20..24 */
- EIO, EIO, EIO, ENOSPC, EIO, /* 25..29 */
- EIO, EIO, EACCES, EACCES, EIO, /* 30..34 */
- EIO, EIO, EIO, EIO, ENOSPC, /* 35..39 */
- EIO, EIO, EIO, EIO, EIO, /* 40..44 */
- EIO, EIO, EIO, EIO, EIO, /* 45..49 */
- EIO, EIO, EIO, EIO, EBUSY, /* 50..54 */
- EIO, EIO, EIO, EIO, EIO, /* 55..59 */
- EIO, ENOSPC, ENOSPC, EIO, EIO, /* 60..64 */
- EACCES, EIO, EIO, EIO, EIO, /* 65..69 */
- EIO, EIO, EIO, EROFS, EIO, /* 70..74 */
- EIO, EIO, EIO, EIO, EIO, /* 75..79 */
- EEXIST, EIO, ENOENT, EIO, EIO, /* 80..84 */
- EIO, EIO, EINVAL, EIO, EAGAIN, /* 85..89 */
- EIO, EIO, EIO, EIO, EIO, /* 90..94 */
- EINTR, EIO, EIO, EIO, EACCES, /* 95..99 */
- ENOMEM, EINVAL, EINVAL, ENOMEM, EINVAL, /* 100..104 */
- EINVAL, ENOMEM, EIO, EACCES, EPIPE, /* 105..109 */
- ENOENT, E2BIG, ENOSPC, ENOMEM, EBADF, /* 110..114 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 115..119 */
- EINVAL, EINVAL, EINVAL, ENOENT, EINVAL, /* 120..124 */
- ENOENT, ENOENT, ENOENT, ECHILD, ECHILD, /* 125..129 */
- EACCES, EINVAL, ESPIPE, EINVAL, EINVAL, /* 130..134 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 135..139 */
- EINVAL, EINVAL, EBUSY, EINVAL, EINVAL, /* 140..144 */
- EINVAL, EINVAL, EINVAL, EBUSY, EINVAL, /* 145..149 */
- EINVAL, EINVAL, ENOMEM, EINVAL, EINVAL, /* 150..154 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 155..159 */
- EINVAL, EINVAL, EINVAL, EINVAL, EAGAIN, /* 160..164 */
- EINVAL, EINVAL, EACCES, EINVAL, EINVAL, /* 165..169 */
- EBUSY, EINVAL, EINVAL, EINVAL, EINVAL, /* 170..174 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 175..179 */
- EINVAL, EINVAL, EINVAL, EINVAL, ECHILD, /* 180..184 */
- EINVAL, EINVAL, ENOENT, EINVAL, EINVAL, /* 185..189 */
- ENOEXEC,ENOEXEC,ENOEXEC,ENOEXEC,ENOEXEC, /* 190..194 */
- ENOEXEC,ENOEXEC,ENOEXEC,ENOEXEC,ENOEXEC, /* 195..199 */
- ENOEXEC,ENOEXEC,ENOEXEC,ENOENT, EINVAL, /* 200..204 */
- EINVAL, ENAMETOOLONG, EINVAL, EINVAL, EINVAL, /* 205..209 */
- EINVAL, EINVAL, EACCES, ENOEXEC,ENOEXEC, /* 210..214 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 215..219 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 220..224 */
- EINVAL, EINVAL, EINVAL, ECHILD, EINVAL, /* 225..229 */
- EINVAL, EBUSY, EAGAIN, ENOTCONN, EINVAL, /* 230..234 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 235..239 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 240..244 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 245..249 */
- EACCES, EACCES, EINVAL, ENOENT, EINVAL, /* 250..254 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 255..259 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 260..264 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 265..269 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 270..274 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 275..279 */
- EINVAL, EINVAL, EINVAL, EINVAL, EEXIST, /* 280..284 */
- EEXIST, EINVAL, EINVAL, EINVAL, EINVAL, /* 285..289 */
- ENOMEM, EMFILE, EINVAL, EINVAL, EINVAL, /* 290..294 */
- EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, /* 295..299 */
- EINVAL, EBUSY, EINVAL, ESRCH, EINVAL, /* 300..304 */
- ESRCH, EINVAL, EINVAL, EINVAL, ESRCH, /* 305..309 */
- EINVAL, ENOMEM, EINVAL, EINVAL, EINVAL, /* 310..314 */
- EINVAL, E2BIG, ENOENT, EIO, EIO, /* 315..319 */
- EINVAL, EINVAL, EINVAL, EINVAL, EAGAIN, /* 320..324 */
- EINVAL, EINVAL, EINVAL, EIO, ENOENT, /* 325..329 */
- EACCES, EACCES, EACCES, ENOENT, ENOMEM /* 330..334 */
-};
-
-/*
- * Initialize 64bit file access: dynamic load of WSeB API
-*/
- File64bit :: File64bit()
-{
- HMODULE hDoscalls;
-
- if (DosQueryModuleHandle("DOSCALLS", &hDoscalls) != NO_ERROR)
- return;
-
- if (DosQueryProcAddr(hDoscalls, 981, NULL, (PFN *)&_DosOpenL) != NO_ERROR)
- return;
-
- if (DosQueryProcAddr(hDoscalls, 988, NULL, (PFN *)&_DosSetFilePtrL) != NO_ERROR) {
- _DosOpenL = NULL;
- return;
- }
-
- if (DosQueryProcAddr(hDoscalls, 986, NULL, (PFN *)&_DosSetFileLocksL) != NO_ERROR) {
- _DosOpenL = NULL;
- _DosSetFilePtrL = NULL;
- return;
- }
- /* notify success */
-#ifdef MYSQL_SERVER
- printf( "WSeB 64bit file API loaded.\n");
-#endif
-}
-
-void _OS2errno( APIRET rc)
-{
- if (rc >= sizeof (errno_tab))
- errno = EINVAL;
- else
- errno = errno_tab[rc];
-}
-
-
-longlong _lseek64( int fd, longlong offset, int seektype)
-{
- APIRET rc;
- longlong actual;
-
- if (_DosSetFilePtrL)
- rc = _DosSetFilePtrL( fd, offset, seektype, &actual);
- else
- {
- ULONG ulActual;
- rc = DosSetFilePtr( fd, (long) offset, seektype, &ulActual);
- actual = ulActual;
- }
-
- if (!rc)
- return( actual); /* NO_ERROR */
-
- _OS2errno( rc); /* set errno */
- return(-1); /* seek failed */
-}
-
-
-inline APIRET _SetFileLocksL(HFILE hFile,
- PFILELOCKL pflUnlock,
- PFILELOCKL pflLock,
- ULONG timeout,
- ULONG flags)
-{
- if (_DosSetFileLocksL)
- {
- APIRET rc;
- rc = _DosSetFileLocksL( hFile, pflUnlock, pflLock, timeout, flags);
-
- /*
- on FAT/HPFS/LAN a INVALID_PARAMETER is returned, seems that
- only JFS can handle >2GB ranges.
- */
- if (rc != 87)
- return rc;
- /* got INVALID_PARAMETER, fallback to standard call */
- }
-
- FILELOCK flUnlock = { pflUnlock->lOffset, pflUnlock->lRange };
- FILELOCK flLock = { pflLock->lOffset, pflLock->lRange };
- return DosSetFileLocks( hFile, &flUnlock, &flLock, timeout, flags);
-}
-
-
-int _lock64( int fd, int locktype, my_off_t start,
- my_off_t length, myf MyFlags)
-{
- FILELOCKL LockArea = {0,0}, UnlockArea = {0,0};
- ULONG readonly = 0;
- APIRET rc = -1;
-
- switch (locktype) {
- case F_UNLCK:
- UnlockArea.lOffset = start;
- UnlockArea.lRange = length ? length : LONGLONG_MAX;
- break;
-
- case F_RDLCK:
- case F_WRLCK:
- LockArea.lOffset = start;
- LockArea.lRange = length ? length : LONGLONG_MAX;
- readonly = (locktype == F_RDLCK ? 1 : 0);
- break;
-
- default:
- errno = EINVAL;
- rc = -1;
- break;
- }
-
- if (MyFlags & MY_DONT_WAIT)
- {
- rc = _SetFileLocksL( fd, &UnlockArea, &LockArea, 0, readonly);
- /* printf("fd %d, locktype %d, rc %d (dont_wait)\n", fd, locktype, rc); */
- if (rc == 33) { /* Lock Violation */
-
- DBUG_PRINT("info",("Was locked, trying with timeout"));
- rc = _SetFileLocksL( fd, &UnlockArea, &LockArea, 1 * 1000, readonly);
- /* printf( "fd %d, locktype %d, rc %d (dont_wait with timeout)\n", fd, locktype, rc); */
- }
- }
- else
- {
- while (rc = _SetFileLocksL( fd, &UnlockArea, &LockArea, 0, readonly) &&
- (rc == 33))
- {
- printf(".");
- DosSleep(1 * 1000);
- }
- /* printf( "fd %d, locktype %d, rc %d (wait2)\n", fd, locktype, rc); */
- }
- if (!rc)
- return(0); /* NO_ERROR */
- _OS2errno( rc); /* set errno */
- return(-1); /* lock failed */
-}
-
-
-int sopen(const char *name, int oflag, int shflag, int mask)
-{
- int fail_errno;
- APIRET rc = 0;
- HFILE hf = 0;
- ULONG ulAction = 0;
- LONGLONG cbFile = 0;
- ULONG ulAttribute = FILE_NORMAL;
- ULONG fsOpenFlags = 0;
- ULONG fsOpenMode = 0;
-
- /* Extract the access mode and sharing mode bits. */
- fsOpenMode = (shflag & 0xFF) | (oflag & 0x03);
-
- /*
- Translate ERROR_OPEN_FAILED to ENOENT unless O_EXCL is set (see
- below).
- */
- fail_errno = ENOENT;
-
- /*
- Compute `open_flag' depending on `flags'. Note that _SO_CREAT is
- set for O_CREAT.
- */
-
- if (oflag & O_CREAT)
- {
- if (oflag & O_EXCL)
- {
- fsOpenFlags = OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
- fail_errno = EEXIST;
- }
- else if (oflag & O_TRUNC)
- fsOpenFlags = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
- else
- fsOpenFlags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
-
- if (mask & S_IWRITE)
- ulAttribute = FILE_NORMAL;
- else
- ulAttribute = FILE_READONLY;
-
- }
- else if (oflag & O_TRUNC)
- fsOpenFlags = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
- else
- fsOpenFlags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
-
- /* Try to open the file and handle errors. */
- if (_DosOpenL)
- rc = _DosOpenL( name, &hf, &ulAction, cbFile,
- ulAttribute, fsOpenFlags, fsOpenMode, NULL);
- else
- rc = DosOpen( name, &hf, &ulAction, (LONG) cbFile,
- ulAttribute, fsOpenFlags, fsOpenMode, NULL);
-
- if (rc == ERROR_OPEN_FAILED)
- {
- errno = fail_errno;
- return -1;
- }
- if (rc != 0)
- {
- _OS2errno( rc); /* set errno */
- return -1;
- }
- if (oflag & O_APPEND)
- _lseek64( hf, 0L, SEEK_END);
- return hf;
-}
-
-
-int read(int fd, void *buffer, unsigned int count)
-{
- APIRET rc;
- ULONG actual;
-
- rc= DosRead( fd, (PVOID) buffer, count, &actual);
-
- if (!rc)
- return( actual); /* NO_ERROR */
- _OS2errno( rc); /* set errno */
- return(-1); /* read failed */
-}
-
-
-int write(int fd, const void *buffer, unsigned int count)
-{
- APIRET rc;
- ULONG actual;
-
- rc = DosWrite( fd, (PVOID) buffer, count, &actual);
-
- if (!rc)
- return( actual); /* NO_ERROR */
- _OS2errno( rc); /* set errno */
- return(-1); /* write failed */
-}
-
-
-int close( int fd)
-{
- APIRET rc;
- ULONG actual;
-
- rc = DosClose( fd);
-
- if (!rc)
- return( 0); /* NO_ERROR */
- _OS2errno( rc); /* set errno */
- return(-1); /* close failed */
-}
-
-
-int open( const char *name, int oflag)
-{
- return sopen( name, oflag, OPEN_SHARE_DENYNONE, S_IREAD | S_IWRITE);
-}
-
-
-int open( const char *name, int oflag, int mask)
-{
- return sopen( name, oflag, OPEN_SHARE_DENYNONE, mask);
-}
diff --git a/mysys/my_os2mutex.c b/mysys/my_os2mutex.c
deleted file mode 100644
index 5010d6e8dd5..00000000000
--- a/mysys/my_os2mutex.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
- * All rights reserved.
- *
- * Modified and extended by Antony T Curtis <antony.curtis@olcs.net>
- * for use with OS/2.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by John Birrell.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-#include <stdlib.h>
-#include <errno.h>
-#ifdef _THREAD_SAFE
-
-int
-pthread_mutex_init(pthread_mutex_t * mutex,
- const pthread_mutexattr_t * mutex_attr)
-{
- (void) DosCreateMutexSem(NULL,mutex,0,0);
- return (0); /* Return the completion status: */
-}
-
-
-int
-pthread_mutex_destroy(pthread_mutex_t * mutex)
-{
- APIRET rc;
-
- do
- {
- rc = DosCloseMutexSem(*mutex);
- if (rc == 301) DosReleaseMutexSem(*mutex);
- } while (rc == 301);
-
- *mutex = 0;
- return (0); /* Return the completion status: */
-}
-
-
-int
-pthread_mutex_lock(pthread_mutex_t * mutex)
-{
- APIRET rc;
-
- rc = DosRequestMutexSem(*mutex,SEM_INDEFINITE_WAIT);
- if (rc)
- return(EINVAL);
- return (0); /* Return the completion status: */
-}
-
-
-int
-pthread_mutex_unlock(pthread_mutex_t * mutex)
-{
- (void) DosReleaseMutexSem(*mutex);
- return (0); /* Return the completion status: */
-}
-#endif
diff --git a/mysys/my_os2thread.c b/mysys/my_os2thread.c
deleted file mode 100644
index e34fd18d596..00000000000
--- a/mysys/my_os2thread.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-/*****************************************************************************
-** Simulation of posix threads calls for OS/2
-*****************************************************************************/
-
-#include "mysys_priv.h"
-#if defined(THREAD) && defined(OS2)
-#include <m_string.h>
-#include <process.h>
-
-static pthread_mutex_t THR_LOCK_thread;
-
-struct pthread_map
-{
- HANDLE pthreadself;
- pthread_handler func;
- void * param;
-};
-
-void win_pthread_init(void)
-{
- pthread_mutex_init(&THR_LOCK_thread,NULL);
-}
-
-/*
-** 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)
-{
- DBUG_ENTER("pthread_start");
- 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)); */
- (*func)(func_param);
- DBUG_RETURN(0);
-}
-
-
-int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
- pthread_handler func, void *param)
-{
- HANDLE hThread;
- struct pthread_map *map;
- DBUG_ENTER("pthread_create");
-
- if (!(map=(struct pthread_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);
-#elif defined( OS2)
- hThread=(HANDLE)_beginthread((void( _Optlink *)(void *)) pthread_start, NULL,
- 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);
-
- 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);
- }
-#ifdef OS2
- my_pthread_setprio(hThread, attr->priority);
-#else
- VOID(SetThreadPriority(hThread, attr->priority)) ;
-#endif
- DBUG_RETURN(0);
-}
-
-
-void pthread_exit(void *a)
-{
- _endthread();
-}
-
-/* This is neaded to get the macro pthread_setspecific to work */
-
-int win_pthread_setspecific(void *a,void *b,uint length)
-{
- memcpy(a,b,length);
- return 0;
-}
-
-#endif
diff --git a/mysys/my_os2tls.c b/mysys/my_os2tls.c
deleted file mode 100644
index 49100c65516..00000000000
--- a/mysys/my_os2tls.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* Copyright (C) Yuri Dario & 2000 MySQL AB
- All the above parties has a full, independent copyright to
- the following code, including the right to use the code in
- any manner without any demands from the other parties.
-
- 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 */
-
-DWORD TlsAlloc( void);
-BOOL TlsFree( DWORD);
-PVOID TlsGetValue( DWORD);
-BOOL TlsSetValue( DWORD, PVOID);
-
-#define TLS_MINIMUM_AVAILABLE 64
-
-
-PULONG tls_storage; /* TLS local storage */
-DWORD tls_bits[2]; /* TLS in-use bits */
-pthread_mutex_t tls_mutex; /* TLS mutex for in-use bits */
-
-
-DWORD TlsAlloc( void)
-{
- DWORD index = -1;
- DWORD mask, tibidx;
- int i;
-
- if (tls_storage == NULL)
- {
-
- APIRET rc;
-
- /* allocate memory for TLS storage */
- rc = DosAllocThreadLocalMemory( 1, &tls_storage);
- if (rc)
- fprintf( stderr, "DosAllocThreadLocalMemory error: return code = %u\n",
- rc);
- /* create a mutex */
- if (pthread_mutex_init( &tls_mutex, NULL))
- fprintf( stderr, "Failed to init TLS mutex\n");
- }
-
- pthread_mutex_lock( &tls_mutex);
-
- tibidx = 0;
- if (tls_bits[0] == 0xFFFFFFFF)
- {
- if (tls_bits[1] == 0xFFFFFFFF)
- {
- fprintf( stderr, "tid#%d, no more TLS bits available\n", _threadid);
- pthread_mutex_unlock( &tls_mutex);
- return -1;
- }
- tibidx = 1;
- }
-
- for (i=0; i<32; i++)
- {
- mask = (1 << i);
- if ((tls_bits[ tibidx] & mask) == 0)
- {
- tls_bits[ tibidx] |= mask;
- index = (tibidx*32) + i;
- break;
- }
- }
- tls_storage[index] = 0;
-
- pthread_mutex_unlock( &tls_mutex);
- /* fprintf( stderr, "tid#%d, TlsAlloc index %d\n", _threadid, index); */
- return index;
-}
-
-BOOL TlsFree( DWORD index)
-{
- int tlsidx;
- DWORD mask;
-
- if (index >= TLS_MINIMUM_AVAILABLE)
- return NULL;
-
- pthread_mutex_lock( &tls_mutex);
-
- tlsidx = 0;
- if (index > 32)
- tlsidx++;
-
- mask = (1 << index);
- if (tls_bits[ tlsidx] & mask)
- {
- tls_bits[tlsidx] &= ~mask;
- tls_storage[index] = 0;
- pthread_mutex_unlock( &tls_mutex);
- return TRUE;
- }
-
- pthread_mutex_unlock( &tls_mutex);
- return FALSE;
-}
-
-
-PVOID TlsGetValue( DWORD index)
-{
- if (index >= TLS_MINIMUM_AVAILABLE)
- return NULL;
-
- /* verify if memory has been allocated for this thread */
- if (*tls_storage == NULL)
- {
- /* allocate memory for indexes */
- *tls_storage = (ULONG)calloc( TLS_MINIMUM_AVAILABLE, sizeof(int));
- /* fprintf(stderr, "tid#%d, tls_storage %x\n", _threadid, *tls_storage); */
- }
-
- ULONG* tls_array = (ULONG*) *tls_storage;
- return (PVOID) tls_array[index];
-}
-
-
-BOOL TlsSetValue( DWORD index, PVOID val)
-{
-
- /* verify if memory has been allocated for this thread */
- if (*tls_storage == NULL)
- {
- /* allocate memory for indexes */
- *tls_storage = (ULONG)calloc( TLS_MINIMUM_AVAILABLE, sizeof(int));
- /* fprintf(stderr, "tid#%d, tls_storage %x\n", _threadid, *tls_storage); */
- }
-
- if (index >= TLS_MINIMUM_AVAILABLE)
- return FALSE;
-
- ULONG* tls_array = (ULONG*) *tls_storage;
- /* fprintf( stderr, "tid#%d, TlsSetValue array %08x index %d -> %08x (old)\n", _threadid, tls_array, index, tls_array[ index]); */
- tls_array[ index] = (ULONG) val;
- /* fprintf( stderr, "tid#%d, TlsSetValue array %08x index %d -> %08x\n", _threadid, tls_array, index, val); */
- return TRUE;
-}
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index 2d42a6ebbc4..6e98132db73 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -20,17 +20,36 @@
#include <unistd.h>
#endif
- /* Read a chunk of bytes from a file */
+/*
+ Read a chunk of bytes from a file from a given position
-uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
- myf MyFlags)
+ SYNOPSIOS
+ my_pread()
+ Filedes File decsriptor
+ Buffer Buffer to read data into
+ Count Number of bytes to read
+ offset Position to read from
+ MyFlags Flags
+
+ NOTES
+ This differs from the normal pread() call in that we don't care
+ to set the position in the file back to the original position
+ if the system doesn't support pread().
+
+ RETURN
+ (size_t) -1 Error
+ # Number of bytes read
+*/
+
+size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
+ myf MyFlags)
{
- uint readbytes;
- int error;
+ size_t readbytes;
+ int error= 0;
DBUG_ENTER("my_pread");
DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
- Filedes, (ulong) offset, (long) Buffer, Count, MyFlags));
-
+ Filedes, (ulong) offset, (long) Buffer, (uint) Count,
+ MyFlags));
for (;;)
{
#ifndef __WIN__
@@ -39,19 +58,19 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
#ifndef HAVE_PREAD
pthread_mutex_lock(&my_file_info[Filedes].mutex);
readbytes= (uint) -1;
- error= (lseek(Filedes, offset, MY_SEEK_SET) == -1L ||
- (readbytes = (uint) read(Filedes, Buffer, Count)) != Count);
+ error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
+ (readbytes= read(Filedes, Buffer, Count)) != Count);
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
#else
- error=((readbytes = (uint) pread(Filedes, Buffer, Count, offset)) != Count);
+ if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
+ my_errno= errno;
#endif
- if (error)
+ if (error || readbytes != Count)
{
- my_errno=errno;
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
- (int) readbytes, Count,Filedes,my_errno));
+ (int) readbytes, (uint) Count,Filedes,my_errno));
#ifdef THREAD
- if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
+ if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
{
DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d",
(int) readbytes));
@@ -60,14 +79,14 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
#endif
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
- if ((int) readbytes == -1)
+ 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 ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
}
if (MyFlags & (MY_NABP | MY_FNABP))
@@ -77,42 +96,63 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
} /* my_pread */
- /* Write a chunk of bytes to a file */
+/*
+ Write a chunk of bytes to a file at a given position
-uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
- myf MyFlags)
+ SYNOPSIOS
+ my_pwrite()
+ Filedes File decsriptor
+ Buffer Buffer to write data from
+ Count Number of bytes to write
+ offset Position to write to
+ MyFlags Flags
+
+ NOTES
+ This differs from the normal pwrite() call in that we don't care
+ to set the position in the file back to the original position
+ if the system doesn't support pwrite()
+
+ RETURN
+ (size_t) -1 Error
+ # Number of bytes read
+ */
+
+size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
+ my_off_t offset, myf MyFlags)
{
- uint writenbytes,errors;
- ulong written;
+ size_t writenbytes, written;
+ uint errors;
DBUG_ENTER("my_pwrite");
- DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %d MyFlags: %d",
- Filedes, (ulong) offset, (long) Buffer, Count, MyFlags));
- errors=0; written=0L;
+ DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
+ Filedes, (ulong) offset, (long) Buffer, (uint) Count,
+ MyFlags));
+ errors= 0;
+ written= 0;
for (;;)
{
#ifndef HAVE_PREAD
int error;
- writenbytes= (uint) -1;
+ writenbytes= (size_t) -1;
pthread_mutex_lock(&my_file_info[Filedes].mutex);
- error=(lseek(Filedes, offset, MY_SEEK_SET) != -1L &&
- (writenbytes = (uint) write(Filedes, Buffer, Count)) == Count);
+ error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
+ (writenbytes = write(Filedes, Buffer, Count)) == Count);
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
if (error)
break;
#else
- if ((writenbytes = (uint) pwrite(Filedes, Buffer, Count,offset)) == Count)
+ if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count)
break;
+ my_errno= errno;
#endif
- if ((int) writenbytes != -1)
+ if (writenbytes != (size_t) -1)
{ /* Safegueard */
written+=writenbytes;
Buffer+=writenbytes;
Count-=writenbytes;
offset+=writenbytes;
}
- my_errno=errno;
- DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+ DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
@@ -127,8 +167,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
continue;
}
- if ((writenbytes > 0 && (uint) writenbytes != (uint) -1) ||
- my_errno == EINTR)
+ if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
continue; /* Retry */
#endif
if (MyFlags & (MY_NABP | MY_FNABP))
@@ -143,6 +182,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
else
break; /* Return bytes written */
}
+ 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 */
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
index 0422e0c6512..aba3e47d754 100644
--- a/mysys/my_pthread.c
+++ b/mysys/my_pthread.c
@@ -23,7 +23,7 @@
#include <m_string.h>
#include <thr_alarm.h>
-#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
+#if (defined(__BSD__) || defined(_BSDI_VERSION))
#define SCHED_POLICY SCHED_RR
#else
#define SCHED_POLICY SCHED_OTHER
@@ -51,8 +51,6 @@ int my_pthread_getprio(pthread_t thread_id)
int policy;
if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
{
- DBUG_PRINT("thread",("policy: %d priority: %d",
- policy,tmp_sched_param.sched_priority));
return tmp_sched_param.sched_priority;
}
#endif
@@ -77,9 +75,6 @@ void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
#undef pthread_getspecific
-#ifdef HAVE_UNIXWARE7_THREADS
-#define pthread_getspecific thr_getspecific
-#endif
void *my_pthread_getspecific_imp(pthread_key_t key)
{
@@ -191,7 +186,7 @@ struct tm *gmtime_r(const time_t *clock, struct tm *res)
** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
****************************************************************************/
-#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(OS2)
+#if !defined(HAVE_SIGWAIT) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
#if !defined(DONT_USE_SIGSUSPEND)
@@ -430,7 +425,7 @@ int sigwait(sigset_t *setp, int *sigp)
** Patches for AIX and DEC OSF/1 3.2
*****************************************************************************/
-#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
+#if defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT)
#include <netdb.h>
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
index 15549dfb751..c19fe08572d 100644
--- a/mysys/my_quick.c
+++ b/mysys/my_quick.c
@@ -19,14 +19,14 @@
#include "my_nosys.h"
-uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
+size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
{
- uint readbytes;
+ size_t readbytes;
- if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+ if ((readbytes = read(Filedes, Buffer, Count)) != Count)
{
#ifndef DBUG_OFF
- if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR)
+ 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!",
@@ -40,20 +40,20 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
}
-uint my_quick_write(File Filedes,const byte *Buffer,uint Count)
+size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
{
#ifndef DBUG_OFF
- uint writtenbytes;
+ size_t writtenbytes;
#endif
if ((
#ifndef DBUG_OFF
writtenbytes =
#endif
- (uint) write(Filedes,Buffer,Count)) != Count)
+ (size_t) write(Filedes,Buffer,Count)) != Count)
{
#ifndef DBUG_OFF
- if ((writtenbytes == 0 || (int) writtenbytes == -1) && errno == EINTR)
+ 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!",
@@ -61,7 +61,7 @@ uint my_quick_write(File Filedes,const byte *Buffer,uint Count)
}
#endif
my_errno=errno;
- return (uint) -1;
+ return (size_t) -1;
}
return 0;
}
diff --git a/mysys/my_read.c b/mysys/my_read.c
index a6c45340b0c..f3e8a4b300e 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -33,43 +33,44 @@
N number of bytes read.
*/
-uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
+size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
{
- uint readbytes, save_count;
+ size_t readbytes, save_count;
DBUG_ENTER("my_read");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %u MyFlags: %d",
- Filedes, (long) Buffer, Count, MyFlags));
+ DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
+ Filedes, (long) Buffer, (ulong) Count, MyFlags));
save_count= Count;
for (;;)
{
errno= 0; /* Linux doesn't reset this */
- if ((readbytes= (uint) read(Filedes, Buffer, Count)) != Count)
+ if ((readbytes= read(Filedes, Buffer, Count)) != Count)
{
my_errno= errno ? errno : -1;
- DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
- (int) readbytes, Count, Filedes, my_errno));
+ 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 %d",
- (int) readbytes));
+ DBUG_PRINT("debug", ("my_read() was interrupted and returned %ld",
+ (long) readbytes));
continue; /* Interrupted */
}
#endif
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
- if ((int) readbytes == -1)
+ 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 ((int) readbytes == -1 ||
+ if (readbytes == (size_t) -1 ||
((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
- if (readbytes > 0 && (MyFlags & MY_FULL_IO))
+ if (readbytes != (size_t) -1 && (MyFlags & MY_FULL_IO))
{
Buffer+= readbytes;
Count-= readbytes;
diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c
index 43fbb0c1eee..c7cf1323cd4 100644
--- a/mysys/my_realloc.c
+++ b/mysys/my_realloc.c
@@ -22,12 +22,12 @@
/* My memory re allocator */
-gptr my_realloc(gptr oldpoint, uint size, myf my_flags)
+void* my_realloc(void* oldpoint, size_t size, myf my_flags)
{
- gptr point;
+ void *point;
DBUG_ENTER("my_realloc");
- DBUG_PRINT("my",("ptr: 0x%lx size: %u my_flags: %d", (long) oldpoint, size,
- my_flags));
+ DBUG_PRINT("my",("ptr: 0x%lx size: %lu my_flags: %d", (long) oldpoint,
+ (ulong) size, my_flags));
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
DBUG_RETURN(my_malloc(size,my_flags));
@@ -48,7 +48,7 @@ gptr my_realloc(gptr oldpoint, uint size, myf my_flags)
free(oldpoint);
}
#else
- if ((point = (char*)realloc(oldpoint,size)) == NULL)
+ if ((point= (uchar*) realloc(oldpoint,size)) == NULL)
{
if (my_flags & MY_FREE_ON_ERROR)
my_free(oldpoint, my_flags);
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
index 0aec395cf65..b12cf098283 100644
--- a/mysys/my_redel.c
+++ b/mysys/my_redel.c
@@ -13,7 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES /* sys/types is included */
#include "mysys_priv.h"
#include <my_dir.h>
#include <m_string.h>
@@ -89,14 +88,14 @@ int my_copystat(const char *from, const char *to, int MyFlags)
return 1;
VOID(chmod(to, statbuf.st_mode & 07777)); /* Copy modes */
-#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) && !defined(__NETWARE__)
+#if !defined(__WIN__) && !defined(__NETWARE__)
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);
}
VOID(chown(to, statbuf.st_uid, statbuf.st_gid)); /* Copy ownership */
-#endif /* MSDOS */
+#endif /* !__WIN__ && !__NETWARE__ */
#ifndef VMS
#ifndef __ZTC__
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
index c4aeb95b2c0..6a6aa6a5796 100644
--- a/mysys/my_rename.c
+++ b/mysys/my_rename.c
@@ -13,7 +13,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define USES_TYPES
#include "mysys_priv.h"
#include <my_dir.h>
#include "mysys_err.h"
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index 5c1a6c44b6f..2c661baeff7 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -45,7 +45,7 @@
my_off_t my_seek(File fd, my_off_t pos, int whence,
myf MyFlags __attribute__((unused)))
{
- reg1 os_off_t newpos;
+ reg1 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,
diff --git a/mysys/my_sleep.c b/mysys/my_sleep.c
index 50e6fae17fc..87170e4af41 100644
--- a/mysys/my_sleep.c
+++ b/mysys/my_sleep.c
@@ -24,8 +24,6 @@ void my_sleep(ulong m_seconds)
delay(m_seconds/1000+1);
#elif defined(__WIN__)
Sleep(m_seconds/1000+1); /* Sleep() has millisecond arg */
-#elif defined(OS2)
- DosSleep(m_seconds/1000+1);
#elif defined(HAVE_SELECT)
struct timeval t;
t.tv_sec= m_seconds / 1000000L;
diff --git a/mysys/my_static.c b/mysys/my_static.c
index 77dbffb911e..cb482b19b57 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -18,20 +18,19 @@
a shared library
*/
-#if !defined(stdin) || defined(OS2)
#include "mysys_priv.h"
#include "my_static.h"
#include "my_alarm.h"
-#endif
my_bool timed_mutexes= 0;
/* from my_init */
-my_string home_dir=0;
+char * home_dir=0;
const char *my_progname=0;
char NEAR curr_dir[FN_REFLEN]= {0},
NEAR 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;
@@ -48,9 +47,6 @@ struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
sigset_t my_signals; /* signals blocked by mf_brkhant */
#endif
- /* from mf_keycache.c */
-my_bool key_cache_inited=0;
-
/* from mf_reccache.c */
ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
@@ -77,8 +73,8 @@ uint sf_malloc_prehunc=0, /* If you have problem with core- */
ulong sf_malloc_cur_memory= 0L; /* Current memory usage */
ulong sf_malloc_max_memory= 0L; /* Maximum memory usage */
uint sf_malloc_count= 0; /* Number of times NEW() was called */
-byte *sf_min_adress= (byte*) ~(unsigned long) 0L,
- *sf_max_adress= (byte*) 0L;
+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;
@@ -86,13 +82,6 @@ struct st_irem *sf_malloc_root = NULL;
int volatile my_have_got_alarm=0; /* declare variable to reset */
ulong my_time_to_wait_for_lock=2; /* In seconds */
- /*
- We need to have this define here as otherwise linking will fail
- on OSF1 when compiling --without-raid --with-debug
- */
-
-const char *raid_type_string[]={"none","striped"};
-
/* from errors.c */
#ifdef SHARED_LIBRARY
char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
@@ -103,6 +92,11 @@ int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
my_message_no_curses;
+#ifdef __WIN__
+/* from my_getsystime.c */
+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;
diff --git a/mysys/my_static.h b/mysys/my_static.h
index b438c936225..0eca196c1c9 100644
--- a/mysys/my_static.h
+++ b/mysys/my_static.h
@@ -60,12 +60,14 @@ extern const char *soundex_map;
extern USED_MEM* my_once_root_block;
extern uint my_once_extra;
-extern byte *sf_min_adress,*sf_max_adress;
+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
diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c
index e2493874097..2a46fb3abea 100644
--- a/mysys/my_symlink2.c
+++ b/mysys/my_symlink2.c
@@ -33,9 +33,13 @@ File my_create_with_symlink(const char *linkname, const char *filename,
int create_link;
char abs_linkname[FN_REFLEN];
DBUG_ENTER("my_create_with_symlink");
+ DBUG_PRINT("enter", ("linkname: %s filename: %s",
+ linkname ? linkname : "(null)",
+ filename ? filename : "(null)"));
if (my_disable_symlinks)
{
+ DBUG_PRINT("info", ("Symlinks disabled"));
/* Create only the file, not the link and file */
create_link= 0;
if (linkname)
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index c446808c7da..1ba6e5ac92d 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -30,7 +30,7 @@ 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_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time;
pthread_cond_t THR_COND_threads;
uint THR_thread_count= 0;
uint my_thread_end_wait_time= 5;
@@ -50,12 +50,12 @@ pthread_mutexattr_t my_errorcheck_mutexattr;
#ifdef TARGET_OS_LINUX
/*
- Dummy thread spawned in my_thread_global_init() below to avoid
- race conditions in NPTL pthread_exit code.
+ Dummy thread spawned in my_thread_global_init() below to avoid
+ race conditions in NPTL pthread_exit code.
*/
static pthread_handler_t
-nptl_pthread_exit_hack_handler(void *arg __attribute__((unused)))
+nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
{
/* Do nothing! */
pthread_exit(0);
@@ -64,6 +64,7 @@ nptl_pthread_exit_hack_handler(void *arg __attribute__((unused)))
#endif /* TARGET_OS_LINUX */
+
static uint get_thread_lib(void);
/*
@@ -146,6 +147,7 @@ my_bool my_thread_global_init(void)
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();
@@ -209,6 +211,7 @@ void my_thread_global_end(void)
pthread_mutex_destroy(&THR_LOCK_myisam);
pthread_mutex_destroy(&THR_LOCK_heap);
pthread_mutex_destroy(&THR_LOCK_net);
+ pthread_mutex_destroy(&THR_LOCK_time);
pthread_mutex_destroy(&THR_LOCK_charset);
if (all_threads_killed)
{
@@ -223,7 +226,7 @@ void my_thread_global_end(void)
#endif
}
-static long thread_id=0;
+static my_thread_id thread_id= 0;
/*
Allocate thread specific memory for the thread, used by mysys and dbug
@@ -251,15 +254,16 @@ my_bool my_thread_init(void)
my_bool error=0;
#ifdef EXTRA_DEBUG_THREADS
- fprintf(stderr,"my_thread_init(): thread_id=%ld\n",pthread_self());
+ fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
+ (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
- fprintf(stderr,"my_thread_init() called more than once in thread %ld\n",
- pthread_self());
+ fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
+ (long) pthread_self());
#endif
goto end;
}
@@ -279,7 +283,9 @@ my_bool my_thread_init(void)
tmp= &THR_KEY_mysys;
#endif
#if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
- tmp->thread_self= (pthread_t)getpid();
+ 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);
@@ -289,6 +295,11 @@ my_bool my_thread_init(void)
tmp->id= ++thread_id;
++THR_thread_count;
pthread_mutex_unlock(&THR_LOCK_threads);
+#ifndef DBUG_OFF
+ /* Generate unique name for thread */
+ (void) my_thread_name();
+#endif
+
end:
return error;
}
@@ -312,8 +323,8 @@ void my_thread_end(void)
tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
#ifdef EXTRA_DEBUG_THREADS
- fprintf(stderr,"my_thread_end(): tmp: 0x%lx thread_id=%ld\n",
- (long) tmp, pthread_self());
+ 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
if (tmp && tmp->init)
{
@@ -325,12 +336,12 @@ void my_thread_end(void)
tmp->dbug=0;
}
#endif
-#if !defined(__bsdi__) && !defined(__OpenBSD__) || defined(HAVE_mit_thread)
+#if !defined(__bsdi__) && !defined(__OpenBSD__)
/* bsdi and openbsd 3.5 dumps core here */
pthread_cond_destroy(&tmp->suspend);
#endif
pthread_mutex_destroy(&tmp->mutex);
-#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS)
+#if !defined(__WIN__) || defined(USE_TLS)
free(tmp);
#else
tmp->init= 0;
@@ -349,7 +360,7 @@ void my_thread_end(void)
pthread_mutex_unlock(&THR_LOCK_threads);
}
/* The following free has to be done, even if my_thread_var() is 0 */
-#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS)
+#if !defined(__WIN__) || defined(USE_TLS)
pthread_setspecific(THR_KEY_mysys,0);
#endif
}
@@ -374,17 +385,9 @@ struct st_my_thread_var *_my_thread_var(void)
Get name of current thread.
****************************************************************************/
-#define UNKNOWN_THREAD -1
-
-long my_thread_id()
+my_thread_id my_thread_dbug_id()
{
-#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
- return pthread_getsequence_np(pthread_self());
-#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) && !defined(HAVE_mit_thread)
- return pthread_self();
-#else
return my_thread_var->id;
-#endif
}
#ifdef DBUG_OFF
@@ -401,8 +404,8 @@ const char *my_thread_name(void)
struct st_my_thread_var *tmp=my_thread_var;
if (!tmp->name[0])
{
- long id=my_thread_id();
- sprintf(name_buff,"T@%ld", id);
+ my_thread_id id= my_thread_dbug_id();
+ sprintf(name_buff,"T@%lu", (ulong) id);
strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
}
return tmp->name;
diff --git a/mysys/my_vle.c b/mysys/my_vle.c
new file mode 100644
index 00000000000..09f297eb553
--- /dev/null
+++ b/mysys/my_vle.c
@@ -0,0 +1,109 @@
+/* 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 */
+
+/*
+ Variable length encoding.
+
+ A method to store an arbitrary-size non-negative integer. We let the
+ most significant bit of the number indicate that the next byte
+ should be contatenated to form the real number.
+*/
+
+#include "my_vle.h"
+
+/*
+ Function to encode an unsigned long as VLE. The bytes for the VLE
+ will be written to the location pointed to by 'out'. The maximum
+ number of bytes written will be 'max'.
+
+ PARAMETERS
+
+ out Pointer to beginning of where to store VLE bytes.
+ max Maximum number of bytes to write.
+ n Number to encode.
+
+ RETURN VALUE
+ On success, one past the end of the array containing the VLE
+ bytes. On failure, the 'out' pointer is returned.
+*/
+
+uchar*
+my_vle_encode(uchar* out, size_t max, ulong n)
+{
+ uchar buf[my_vle_sizeof(n)];
+ uchar *ptr= buf;
+ size_t len;
+
+ do
+ {
+ *ptr++= (uchar) (n & 0x7F);
+ n>>= 7;
+ }
+ while (n > 0);
+
+ len= ptr - buf;
+
+ if (len <= max)
+ {
+ /*
+ The bytes are stored in reverse order in 'buf'. Let's write them
+ in correct order to the output buffer and set the MSB at the
+ same time.
+ */
+ while (ptr-- > buf)
+ {
+ uchar v= *ptr;
+ if (ptr > buf)
+ v|= 0x80;
+ *out++= v;
+ }
+ }
+
+ return out;
+}
+
+/*
+ Function to decode a VLE representation of an integral value.
+
+
+ PARAMETERS
+
+ result_ptr Pointer to an unsigned long where the value will be written.
+ vle Pointer to the VLE bytes.
+
+ RETURN VALUE
+
+ One-past the end of the VLE bytes. The routine will never read
+ more than sizeof(*result_ptr) + 1 bytes.
+*/
+
+uchar const*
+my_vle_decode(ulong *result_ptr, uchar const *vle)
+{
+ ulong result= 0;
+ size_t cnt= 1;
+
+ do
+ {
+ result<<= 7;
+ result|= (*vle & 0x7F);
+ }
+ while ((*vle++ & 0x80) && ++cnt <= sizeof(*result_ptr) + 1);
+
+ if (cnt <= sizeof(*result_ptr) + 1)
+ *result_ptr= result;
+
+ return vle;
+}
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index 353b2fced4e..d1b07b61408 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -201,7 +201,7 @@ int pthread_attr_setprio(pthread_attr_t *connect_att,int priority)
int pthread_attr_destroy(pthread_attr_t *connect_att)
{
- bzero((gptr) connect_att,sizeof(*connect_att));
+ bzero((uchar*) connect_att,sizeof(*connect_att));
return 0;
}
diff --git a/mysys/my_windac.c b/mysys/my_windac.c
index c711093b48f..f846853f7be 100644
--- a/mysys/my_windac.c
+++ b/mysys/my_windac.c
@@ -194,8 +194,8 @@ error:
FreeSid(everyone_sid);
if (htoken)
CloseHandle(htoken);
- my_free((gptr) sa, MYF(MY_ALLOW_ZERO_PTR));
- my_free((gptr) dacl, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) sa, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) dacl, MYF(MY_ALLOW_ZERO_PTR));
*psa= 0;
return 1;
}
@@ -215,8 +215,8 @@ void my_security_attr_free(SECURITY_ATTRIBUTES *sa)
My_security_attr *attr= (My_security_attr*)
(((char*)sa) + ALIGN_SIZE(sizeof(*sa)));
FreeSid(attr->everyone_sid);
- my_free((gptr) attr->dacl, MYF(0));
- my_free((gptr) sa, MYF(0));
+ my_free((uchar*) attr->dacl, MYF(0));
+ my_free((uchar*) sa, MYF(0));
}
}
diff --git a/mysys/my_write.c b/mysys/my_write.c
index 4c3d187e4e8..056a84f1794 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -20,28 +20,28 @@
/* Write a chunk of bytes to a file */
-uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
+size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
{
- uint writenbytes,errors;
- ulong written;
+ size_t writenbytes, written;
+ uint errors;
DBUG_ENTER("my_write");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %d MyFlags: %d",
- Filedes, (long) Buffer, Count, MyFlags));
- errors=0; written=0L;
+ DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
+ Filedes, (long) Buffer, (ulong) Count, MyFlags));
+ errors=0; written=0;
for (;;)
{
- if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+ if ((writenbytes= write(Filedes, Buffer, Count)) == Count)
break;
- if ((int) writenbytes != -1)
+ if (writenbytes != (size_t) -1)
{ /* Safeguard */
written+=writenbytes;
Buffer+=writenbytes;
Count-=writenbytes;
}
my_errno=errno;
- DBUG_PRINT("error",("Write only %d bytes, error: %d",
- writenbytes,my_errno));
+ DBUG_PRINT("error",("Write only %ld bytes, error: %d",
+ (long) writenbytes, my_errno));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
@@ -57,12 +57,12 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
continue;
}
- if ((writenbytes == 0 || (int) writenbytes == -1))
+ if ((writenbytes == 0 || writenbytes == (size_t) -1))
{
if (my_errno == EINTR)
{
- DBUG_PRINT("debug", ("my_write() was interrupted and returned %d",
- (int) writenbytes));
+ DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld",
+ (long) writenbytes));
continue; /* Interrupted */
}
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index 8a636e94626..6e0959ae08c 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -28,7 +28,7 @@
#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;
+extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
#else
#include <my_no_pthread.h>
#endif
@@ -40,3 +40,5 @@ extern pthread_mutex_t THR_LOCK_charset;
#ifndef EDQUOT
#define EDQUOT (-1)
#endif
+
+void my_error_unregister_all(void);
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
index 33c28160a4c..24ab6a1ea9c 100644
--- a/mysys/ptr_cmp.c
+++ b/mysys/ptr_cmp.c
@@ -22,15 +22,15 @@
#include "mysys_priv.h"
#include <myisampack.h>
-static int ptr_compare(uint *compare_length, uchar **a, uchar **b);
-static int ptr_compare_0(uint *compare_length, uchar **a, uchar **b);
-static int ptr_compare_1(uint *compare_length, uchar **a, uchar **b);
-static int ptr_compare_2(uint *compare_length, uchar **a, uchar **b);
-static int ptr_compare_3(uint *compare_length, uchar **a, uchar **b);
+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);
/* Get a pointer to a optimal byte-compare function for a given size */
-qsort2_cmp get_ptr_compare (uint size)
+qsort2_cmp get_ptr_compare (size_t size)
{
if (size < 4)
return (qsort2_cmp) ptr_compare;
@@ -51,7 +51,7 @@ qsort2_cmp get_ptr_compare (uint size)
#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
-static int ptr_compare(uint *compare_length, uchar **a, uchar **b)
+static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
{
reg3 int length= *compare_length;
reg1 uchar *first,*last;
@@ -66,7 +66,7 @@ static int ptr_compare(uint *compare_length, uchar **a, uchar **b)
}
-static int ptr_compare_0(uint *compare_length,uchar **a, uchar **b)
+static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b)
{
reg3 int length= *compare_length;
reg1 uchar *first,*last;
@@ -87,7 +87,7 @@ static int ptr_compare_0(uint *compare_length,uchar **a, uchar **b)
}
-static int ptr_compare_1(uint *compare_length,uchar **a, uchar **b)
+static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b)
{
reg3 int length= *compare_length-1;
reg1 uchar *first,*last;
@@ -108,7 +108,7 @@ static int ptr_compare_1(uint *compare_length,uchar **a, uchar **b)
return (0);
}
-static int ptr_compare_2(uint *compare_length,uchar **a, uchar **b)
+static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b)
{
reg3 int length= *compare_length-2;
reg1 uchar *first,*last;
@@ -130,7 +130,7 @@ static int ptr_compare_2(uint *compare_length,uchar **a, uchar **b)
return (0);
}
-static int ptr_compare_3(uint *compare_length,uchar **a, uchar **b)
+static int ptr_compare_3(size_t *compare_length,uchar **a, uchar **b)
{
reg3 int length= *compare_length-3;
reg1 uchar *first,*last;
@@ -153,7 +153,7 @@ static int ptr_compare_3(uint *compare_length,uchar **a, uchar **b)
return (0);
}
-void my_store_ptr(byte *buff, uint pack_length, my_off_t pos)
+void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos)
{
switch (pack_length) {
#if SIZEOF_OFF_T > 4
@@ -171,7 +171,7 @@ void my_store_ptr(byte *buff, uint pack_length, my_off_t pos)
return;
}
-my_off_t my_get_ptr(byte *ptr, uint pack_length)
+my_off_t my_get_ptr(uchar *ptr, size_t pack_length)
{
my_off_t pos;
switch (pack_length) {
@@ -184,7 +184,7 @@ my_off_t my_get_ptr(byte *ptr, uint pack_length)
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) mi_uint2korr(ptr); break;
+ case 1: pos= (my_off_t) *(uchar*) ptr; break;
default: DBUG_ASSERT(0); return 0;
}
return pos;
diff --git a/mysys/queues.c b/mysys/queues.c
index 7809c97131c..d8a7ca19bee 100644
--- a/mysys/queues.c
+++ b/mysys/queues.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* 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
@@ -16,6 +16,10 @@
/*
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"
@@ -45,11 +49,11 @@
*/
int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
- pbool max_at_top, int (*compare) (void *, byte *, byte *),
+ pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
void *first_cmp_arg)
{
DBUG_ENTER("init_queue");
- if ((queue->root= (byte **) my_malloc((max_elements+1)*sizeof(void*),
+ if ((queue->root= (uchar **) my_malloc((max_elements+1)*sizeof(void*),
MYF(MY_WME))) == 0)
DBUG_RETURN(1);
queue->elements=0;
@@ -62,6 +66,46 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
}
+
+/*
+ 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
@@ -85,7 +129,7 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
*/
int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
- pbool max_at_top, int (*compare) (void *, byte *, byte *),
+ pbool max_at_top, int (*compare) (void *, uchar *, uchar *),
void *first_cmp_arg)
{
DBUG_ENTER("reinit_queue");
@@ -118,11 +162,11 @@ int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
int resize_queue(QUEUE *queue, uint max_elements)
{
- byte **new_root;
+ uchar **new_root;
DBUG_ENTER("resize_queue");
if (queue->max_elements == max_elements)
DBUG_RETURN(0);
- if ((new_root= (byte **) my_realloc((void *)queue->root,
+ if ((new_root= (uchar **) my_realloc((void *)queue->root,
(max_elements+1)*sizeof(void*),
MYF(MY_WME))) == 0)
DBUG_RETURN(1);
@@ -152,7 +196,7 @@ void delete_queue(QUEUE *queue)
DBUG_ENTER("delete_queue");
if (queue->root)
{
- my_free((gptr) queue->root,MYF(0));
+ my_free((uchar*) queue->root,MYF(0));
queue->root=0;
}
DBUG_VOID_RETURN;
@@ -161,7 +205,7 @@ void delete_queue(QUEUE *queue)
/* Code for insert, search and delete of elements */
-void queue_insert(register QUEUE *queue, byte *element)
+void queue_insert(register QUEUE *queue, uchar *element)
{
reg2 uint idx, next;
int cmp;
@@ -181,12 +225,37 @@ void queue_insert(register QUEUE *queue, byte *element)
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 */
-byte *queue_remove(register QUEUE *queue, uint idx)
+uchar *queue_remove(register QUEUE *queue, uint idx)
{
- byte *element;
+ uchar *element;
DBUG_ASSERT(idx < queue->max_elements);
element= queue->root[++idx]; /* Intern index starts from 1 */
queue->root[idx]= queue->root[queue->elements--];
@@ -203,11 +272,67 @@ void queue_replaced(QUEUE *queue)
}
#endif
- /* Fix heap when index have changed */
+#ifndef OLD_VERSION
+
+void _downheap(register QUEUE *queue, uint idx)
+{
+ uchar *element;
+ uint elements,half_queue,offset_to_key, next_index;
+ 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)
+ {
+ int cmp;
+ 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 &&
+ (((cmp=queue->compare(queue->first_cmp_arg,
+ queue->root[next_index]+offset_to_key,
+ element+offset_to_key)) == 0) ||
+ ((cmp ^ 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)
{
- byte *element;
+ uchar *element;
uint elements,half_queue,next_index,offset_to_key;
int cmp;
@@ -236,20 +361,336 @@ void _downheap(register QUEUE *queue, uint idx)
}
-static int queue_fix_cmp(QUEUE *queue, void **a, void **b)
-{
- return queue->compare(queue->first_cmp_arg,
- (byte*) (*a)+queue->offset_to_key,
- (byte*) (*b)+queue->offset_to_key);
-}
+#endif
/*
- Fix heap when every element was changed,
- actually, it can be done better, in linear time, not in n*log(n)
+ Fix heap when every element was changed.
*/
void queue_fix(QUEUE *queue)
{
- qsort2(queue->root+1,queue->elements, sizeof(void *),
- (qsort2_cmp)queue_fix_cmp, 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
diff --git a/mysys/raid.cc b/mysys/raid.cc
deleted file mode 100644
index 0fbe1810208..00000000000
--- a/mysys/raid.cc
+++ /dev/null
@@ -1,798 +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 */
-
-/*
-
- RAID support for MySQL. Raid 0 (stiping) only implemented yet.
-
- Why RAID? Why it must be in MySQL?
-
- This is because then you can:
- 1. Have bigger tables than your OS limit. In time of writing this
- we are hitting to 2GB limit under linux/ext2
- 2. You can get more speed from IO bottleneck by putting
- Raid dirs on different physical disks.
- 3. Getting more fault tolerance (not implemented yet)
-
- Why not to use RAID:
-
- 1. You are losing some processor power to calculate things,
- do more syscalls and interrupts.
-
- Functionality is supplied by two classes: RaidFd and RaidName.
- RaidFd supports funtionality over file descriptors like
- open/create/write/seek/close. RaidName supports functionality
- like rename/delete where we have no relations to filedescriptors.
- RaidName can be prorably unchanged for different Raid levels. RaidFd
- have to be virtual I think ;).
- You can speed up some calls in MySQL code by skipping RAID code.
- For example LOAD DATA INFILE never needs to read RAID-ed files.
- This can be done adding proper "#undef my_read" or similar undef-s
- in your code. Check out the raid.h!
-
- Some explanation about _seek_vector[]
- This is seek cache. RAID seeks too much and we cacheing this. We
- fool it and just storing new position in file to _seek_vector.
- When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
- Any other value requires seeking to that position.
-
- TODO:
-
-
- - Implement other fancy things like RAID 1 (mirroring) and RAID 5.
- Should not to be very complex.
-
- - Optimize big blob writes by resorting write buffers and writing
- big chunks at once instead of doing many syscalls. - after thinking I
- found this is useless. This is because same thing one can do with just
- increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
-
- - If needed, then implement missing syscalls. One known to miss is stat();
-
- - Make and use a thread safe dynamic_array buffer. The used one
- will not work if needs to be extended at the same time someone is
- accessing it.
-
-
- tonu@mysql.com & monty@mysql.com
-*/
-
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysys_priv.h"
-#include <my_dir.h>
-#include <m_string.h>
-#include <assert.h>
-
-#if defined(USE_RAID) && !defined(MYSQL_CLIENT)
-
-#define RAID_SEEK_DONE ~(off_t) 0
-#define RAID_SIZE_UNKNOWN ~(my_off_t) 0
-
-DYNAMIC_ARRAY RaidFd::_raid_map;
-
-
-/* --------------- C compatibility ---------------*/
-
-extern "C" {
-
- void init_raid(void)
- {
- /* Allocate memory for global file to raid map */
- my_init_dynamic_array(&RaidFd::_raid_map, sizeof(RaidFd*), 4096, 1024);
- }
- void end_raid(void)
- {
- /* Free memory used by raid */
- delete_dynamic(&RaidFd::_raid_map);
- }
-
- bool is_raid(File fd)
- {
- return RaidFd::IsRaid(fd);
- }
-
- File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
- uint raid_type, uint raid_chunks, ulong raid_chunksize,
- myf MyFlags)
- {
- DBUG_ENTER("my_raid_create");
- DBUG_PRINT("enter",("Filename: %s CreateFlags: %d access_flags: %d MyFlags: %d",
- FileName, CreateFlags, access_flags, MyFlags));
- if (raid_type)
- {
- RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
- File res = raid->Create(FileName,CreateFlags,access_flags,MyFlags);
- if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
- {
- delete raid;
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(res);
- }
- else
- DBUG_RETURN(my_create(FileName, CreateFlags, access_flags, MyFlags));
- }
-
- File my_raid_open(const char *FileName, int Flags,
- uint raid_type, uint raid_chunks, ulong raid_chunksize,
- myf MyFlags)
- {
- DBUG_ENTER("my_raid_open");
- DBUG_PRINT("enter",("Filename: %s Flags: %d MyFlags: %d",
- FileName, Flags, MyFlags));
- if (raid_type)
- {
- RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
- File res = raid->Open(FileName,Flags,MyFlags);
- if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
- {
- delete raid;
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(res);
- }
- else
- DBUG_RETURN(my_open(FileName, Flags, MyFlags));
- }
-
- my_off_t my_raid_seek(File fd, my_off_t pos,int whence,myf MyFlags)
- {
- DBUG_ENTER("my_raid_seek");
- DBUG_PRINT("enter",("Fd: %d pos: %lu whence: %d MyFlags: %d",
- fd, (ulong) pos, whence, MyFlags));
-
- if (is_raid(fd))
- {
- assert(pos != MY_FILEPOS_ERROR);
-
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Seek(pos,whence,MyFlags));
- }
- else
- DBUG_RETURN(my_seek(fd, pos, whence, MyFlags));
- }
-
- my_off_t my_raid_tell(File fd,myf MyFlags)
- {
- DBUG_ENTER("my_raid_tell");
- DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
- fd, MyFlags));
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Tell(MyFlags));
- }
- else
- DBUG_RETURN(my_tell(fd, MyFlags));
- }
-
- uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
- {
- DBUG_ENTER("my_raid_write");
- DBUG_PRINT("enter",("Fd: %d Buffer: 0x%lx Count: %u MyFlags: %d",
- fd, Buffer, Count, MyFlags));
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
- } else
- DBUG_RETURN(my_write(fd,Buffer,Count,MyFlags));
- }
-
- uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
- {
- DBUG_ENTER("my_raid_read");
- DBUG_PRINT("enter",("Fd: %d Buffer: 0x%lx Count: %u MyFlags: %d",
- fd, Buffer, Count, MyFlags));
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
- } else
- DBUG_RETURN(my_read(fd,Buffer,Count,MyFlags));
- }
-
- uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
- myf MyFlags)
- {
- DBUG_ENTER("my_raid_pread");
- DBUG_PRINT("enter",
- ("Fd: %d Buffer: 0x%lx Count: %u offset: %u MyFlags: %d",
- Filedes, Buffer, Count, offset, MyFlags));
- if (is_raid(Filedes))
- {
- assert(offset != MY_FILEPOS_ERROR);
-
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
- /* Returning value isn't important because real seek is done later. */
- raid->Seek(offset,MY_SEEK_SET,MyFlags);
- DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
- }
- else
- DBUG_RETURN(my_pread(Filedes, Buffer, Count, offset, MyFlags));
- }
-
- uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
- my_off_t offset, myf MyFlags)
- {
- DBUG_ENTER("my_raid_pwrite");
- DBUG_PRINT("enter",
- ("Fd: %d Buffer: 0x%lx Count: %u offset: %u MyFlags: %d",
- Filedes, Buffer, Count, offset, MyFlags));
- if (is_raid(Filedes))
- {
- assert(offset != MY_FILEPOS_ERROR);
-
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
- /* Returning value isn't important because real seek is done later. */
- raid->Seek(offset,MY_SEEK_SET,MyFlags);
- DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
- }
- else
- DBUG_RETURN(my_pwrite(Filedes, Buffer, Count, offset, MyFlags));
- }
-
- int my_raid_lock(File fd, int locktype, my_off_t start, my_off_t length,
- myf MyFlags)
- {
- DBUG_ENTER("my_raid_lock");
- DBUG_PRINT("enter",("Fd: %d start: %lu length: %lu MyFlags: %d",
- fd, (ulong) start, (ulong) length, MyFlags));
- if (my_disable_locking)
- DBUG_RETURN(0);
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Lock(locktype, start, length, MyFlags));
- }
- else
- DBUG_RETURN(my_lock(fd, locktype, start, length, MyFlags));
- }
-
- int my_raid_close(File fd, myf MyFlags)
- {
- DBUG_ENTER("my_raid_close");
- DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
- fd, MyFlags));
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- RaidFd *tmp=0;
- set_dynamic(&RaidFd::_raid_map,(char*) &tmp,fd);
- int res = raid->Close(MyFlags);
- delete raid;
- DBUG_RETURN(res);
- }
- else
- DBUG_RETURN(my_close(fd, MyFlags));
- }
-
- int my_raid_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
- {
- DBUG_ENTER("my_raid_chsize");
- DBUG_PRINT("enter",("Fd: %d newlength: %lu MyFlags: %d",
- fd, (ulong) newlength, MyFlags));
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Chsize(fd, newlength, filler, MyFlags));
- }
- else
- DBUG_RETURN(my_chsize(fd, newlength, filler, MyFlags));
- }
-
- int my_raid_rename(const char *from, const char *to,
- uint raid_chunks, myf MyFlags)
- {
- char from_tmp[FN_REFLEN];
- char to_tmp[FN_REFLEN];
- DBUG_ENTER("my_raid_rename");
-
- uint from_pos = dirname_length(from);
- uint to_pos = dirname_length(to);
- memcpy(from_tmp, from, from_pos);
- memcpy(to_tmp, to, to_pos);
- for (uint i = 0 ; i < raid_chunks ; i++ )
- {
- sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
- sprintf(to_tmp+to_pos,"%02x/%s", i, to+ to_pos);
- /* Convert if not unix */
- unpack_filename(from_tmp, from_tmp);
- unpack_filename(to_tmp,to_tmp);
- if (my_rename(from_tmp, to_tmp, MyFlags))
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
- }
-
- int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags)
- {
- char from_tmp[FN_REFLEN];
- uint from_pos = dirname_length(from);
- DBUG_ENTER("my_raid_delete");
-
- if (!raid_chunks)
- DBUG_RETURN(my_delete(from,MyFlags));
- for (uint i = 0 ; i < raid_chunks ; i++ )
- {
- memcpy(from_tmp, from, from_pos);
- sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
- /* Convert if not unix */
- unpack_filename(from_tmp, from_tmp);
- if (my_delete(from_tmp, MyFlags))
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
- }
-
- int my_raid_redel(const char *old_name, const char *new_name,
- uint raid_chunks, myf MyFlags)
- {
- char new_name_buff[FN_REFLEN], old_name_buff[FN_REFLEN];
- char *new_end, *old_end;
- uint i,old_length,new_length;
- int error=0;
- DBUG_ENTER("my_raid_redel");
-
- old_end=old_name_buff+dirname_part(old_name_buff,old_name);
- old_length=dirname_length(old_name);
- new_end=new_name_buff+dirname_part(new_name_buff,new_name);
- new_length=dirname_length(new_name);
- for (i=0 ; i < raid_chunks ; i++)
- {
- MY_STAT status;
- sprintf(new_end,"%02x",i);
- if (my_stat(new_name_buff,&status, MYF(0)))
- {
- DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
- }
- else
- {
- if (my_mkdir(new_name_buff,0777,MYF(0)))
- {
- DBUG_PRINT("error",("mkdir failed for %02x",i));
- DBUG_RETURN(-1);
- }
- }
- strxmov(strend(new_end),"/",new_name+new_length,NullS);
- sprintf(old_end,"%02x/%s",i, old_name+old_length);
- if (my_redel(old_name_buff, new_name_buff, MyFlags))
- error=1;
- }
- DBUG_RETURN(error);
- }
-}
-
-int my_raid_fstat(int fd, MY_STAT *stat_area, myf MyFlags )
-{
- DBUG_ENTER("my_raid_fstat");
- if (is_raid(fd))
- {
- RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
- DBUG_RETURN(raid->Fstat(fd, stat_area, MyFlags));
- }
- else
- DBUG_RETURN(my_fstat(fd, stat_area, MyFlags));
-}
-
-
-/* -------------- RaidFd base class begins ----------------*/
-/*
- RaidFd - raided file is identified by file descriptor
- this is useful when we open/write/read/close files
-*/
-
-
-bool RaidFd::
-IsRaid(File fd)
-{
- DBUG_ENTER("RaidFd::IsRaid");
- DBUG_RETURN((uint) fd < _raid_map.elements &&
- *dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
-}
-
-
-RaidFd::
-RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
- :_raid_type(raid_type), _raid_chunks(raid_chunks),
- _raid_chunksize(raid_chunksize), _position(0), _size(RAID_SIZE_UNKNOWN),
- _fd_vector(0)
-{
- DBUG_ENTER("RaidFd::RaidFd");
- DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %lu",
- raid_type, raid_chunks, raid_chunksize));
-
- /* TODO: Here we should add checks if the malloc fails */
- _seek_vector=0; /* In case of errors */
- my_multi_malloc(MYF(MY_WME),
- &_seek_vector,sizeof(off_t)*_raid_chunks,
- &_fd_vector, sizeof(File) *_raid_chunks,
- NullS);
- if (!RaidFd::_raid_map.buffer)
- { /* Not initied */
- pthread_mutex_lock(&THR_LOCK_open); /* Ensure that no other thread */
- if (!RaidFd::_raid_map.buffer) /* has done init in between */
- init_raid();
- pthread_mutex_unlock(&THR_LOCK_open);
- }
- DBUG_VOID_RETURN;
-}
-
-
-RaidFd::
-~RaidFd() {
- DBUG_ENTER("RaidFd::~RaidFd");
- /* We don't have to free _fd_vector ! */
- my_free((char*) _seek_vector, MYF(MY_ALLOW_ZERO_PTR));
- DBUG_VOID_RETURN;
-}
-
-
-File RaidFd::
-Create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags)
-{
- char RaidFdFileName[FN_REFLEN];
- DBUG_ENTER("RaidFd::Create");
- DBUG_PRINT("enter",
- ("FileName: %s CreateFlags: %d access_flags: %d MyFlags: %d",
- FileName, CreateFlags, access_flags, MyFlags));
- char DirName[FN_REFLEN];
- uint pos = dirname_part(DirName, FileName);
- MY_STAT status;
- if (!_seek_vector)
- DBUG_RETURN(-1); /* Not enough memory */
-
- uint i = _raid_chunks-1;
- do
- {
- /* Create subdir */
- (void)sprintf(RaidFdFileName,"%s%02x", DirName,i);
- unpack_dirname(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
- if (my_stat(RaidFdFileName,&status, MYF(0)))
- {
- DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
- }
- else
- {
- if (my_mkdir(RaidFdFileName,0777,MYF(0)))
- {
- DBUG_PRINT("error",("mkdir failed for %d",i));
- goto error;
- }
- }
- /* Create file */
- sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
- unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
- _fd = my_create(RaidFdFileName, CreateFlags ,access_flags, (myf)MyFlags);
- if (_fd < 0)
- goto error;
- _fd_vector[i]=_fd;
- _seek_vector[i]=RAID_SEEK_DONE;
- } while (i--);
- _size=0;
- DBUG_RETURN(_fd); /* Last filenr is pointer to map */
-
-error:
- {
- int save_errno=my_errno;
- while (++i < _raid_chunks)
- {
- my_close(_fd_vector[i],MYF(0));
- sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
- unpack_filename(RaidFdFileName,RaidFdFileName);
- my_delete(RaidFdFileName,MYF(0));
- }
- my_errno=save_errno;
- }
- DBUG_RETURN(-1);
-}
-
-
-File RaidFd::
-Open(const char *FileName, int Flags, myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Open");
- DBUG_PRINT("enter",("FileName: %s Flags: %d MyFlags: %d",
- FileName, Flags, MyFlags));
- char DirName[FN_REFLEN];
- uint pos = dirname_part(DirName, FileName);
- if (!_seek_vector)
- DBUG_RETURN(-1); /* Not enough memory */
-
- for( uint i = 0 ; i < _raid_chunks ; i++ )
- {
- char RaidFdFileName[FN_REFLEN];
- sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
- unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
- _fd = my_open(RaidFdFileName, Flags, MyFlags);
- if (_fd < 0)
- {
- int save_errno=my_errno;
- while (i-- != 0)
- my_close(_fd_vector[i],MYF(0));
- my_errno=save_errno;
- DBUG_RETURN(_fd);
- }
- _fd_vector[i]=_fd;
- _seek_vector[i]=RAID_SEEK_DONE;
- }
- Seek(0L,MY_SEEK_END,MYF(0)); // Trick. We just need to know, how big the file is
- DBUG_PRINT("info",("MYD file logical size: %llu", _size));
- DBUG_RETURN(_fd);
-}
-
-
-int RaidFd::
-Write(const byte *Buffer, uint Count, myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Write");
- DBUG_PRINT("enter",("Count: %d MyFlags: %d",
- Count, MyFlags));
- const byte *bufptr = Buffer;
- uint res=0, GotBytes, ReadNowCount;
-
- // Loop until data is written
- do {
- Calculate();
- // Do seeks when neccessary
- if (_seek_vector[_this_block] != RAID_SEEK_DONE)
- {
- if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
- MY_SEEK_SET,
- MyFlags) == MY_FILEPOS_ERROR)
- DBUG_RETURN(-1);
- _seek_vector[_this_block]=RAID_SEEK_DONE;
- }
- ReadNowCount = min(Count, _remaining_bytes);
- GotBytes = my_write(_fd_vector[_this_block], bufptr, ReadNowCount,
- MyFlags);
- DBUG_PRINT("loop",("Wrote bytes: %d", GotBytes));
- if (GotBytes == MY_FILE_ERROR)
- DBUG_RETURN(-1);
- res+= GotBytes;
- if (MyFlags & (MY_NABP | MY_FNABP))
- GotBytes=ReadNowCount;
- bufptr += GotBytes;
- Count -= GotBytes;
- _position += GotBytes;
- } while(Count);
- set_if_bigger(_size,_position);
- DBUG_RETURN(res);
-}
-
-
-int RaidFd::
-Read(const byte *Buffer, uint Count, myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Read");
- DBUG_PRINT("enter",("Count: %d MyFlags: %d",
- Count, MyFlags));
- byte *bufptr = (byte *)Buffer;
- uint res= 0, GotBytes, ReadNowCount;
-
- // Loop until all data is read (Note that Count may be 0)
- while (Count)
- {
- Calculate();
- // Do seek when neccessary
- if (_seek_vector[_this_block] != RAID_SEEK_DONE)
- {
- if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
- MY_SEEK_SET,
- MyFlags) == MY_FILEPOS_ERROR)
- DBUG_RETURN(-1);
- _seek_vector[_this_block]=RAID_SEEK_DONE;
- }
- // and read
- ReadNowCount = min(Count, _remaining_bytes);
- GotBytes = my_read(_fd_vector[_this_block], bufptr, ReadNowCount,
- MyFlags & ~(MY_NABP | MY_FNABP));
- DBUG_PRINT("loop",("Got bytes: %u", GotBytes));
- if (GotBytes == MY_FILE_ERROR)
- DBUG_RETURN(-1);
- if (!GotBytes) // End of file.
- {
- DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? -1 : (int) res);
- }
- res+= GotBytes;
- bufptr += GotBytes;
- Count -= GotBytes;
- _position += GotBytes;
- }
- DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? 0 : res);
-}
-
-
-int RaidFd::
-Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Lock");
- DBUG_PRINT("enter",("locktype: %d start: %lu length: %lu MyFlags: %d",
- locktype, (ulong) start, (ulong) length, MyFlags));
- my_off_t bufptr = start;
- // Loop until all data is locked
- while(length)
- {
- Calculate();
- for (uint i = _this_block ; (i < _raid_chunks) && length ; i++ )
- {
- uint ReadNowCount = min(length, _remaining_bytes);
- uint GotBytes = my_lock(_fd_vector[i], locktype, bufptr, ReadNowCount,
- MyFlags);
- if ((int) GotBytes == -1)
- DBUG_RETURN(-1);
- bufptr += ReadNowCount;
- length -= ReadNowCount;
- Calculate();
- }
- }
- DBUG_RETURN(0);
-}
-
-
-int RaidFd::
-Close(myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Close");
- DBUG_PRINT("enter",("MyFlags: %d",
- MyFlags));
- for (uint i = 0 ; i < _raid_chunks ; ++i )
- {
- int err = my_close(_fd_vector[i], MyFlags);
- if (err != 0)
- DBUG_RETURN(err);
- }
- /* _fd_vector is erased when RaidFd is released */
- DBUG_RETURN(0);
-}
-
-
-my_off_t RaidFd::
-Seek(my_off_t pos,int whence,myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Seek");
- DBUG_PRINT("enter",("Pos: %lu Whence: %d MyFlags: %d",
- (ulong) pos, whence, MyFlags));
- switch (whence) {
- case MY_SEEK_CUR:
- // FIXME: This is wrong, what is going on there
- // Just I am relied on fact that MySQL 3.23.7 never uses MY_SEEK_CUR
- // for anything else except things like ltell()
- break;
- case MY_SEEK_SET:
- if ( _position != pos) // we can be already in right place
- {
- uint i;
- off_t _rounds;
- _position = pos;
- Calculate();
- _rounds = _total_block / _raid_chunks; // INT() assumed
- _rounds*= _raid_chunksize;
- for (i = 0; i < _raid_chunks ; i++ )
- if ( i < _this_block )
- _seek_vector[i] = _rounds + _raid_chunksize;
- else if ( i == _this_block )
- _seek_vector[i] = _rounds + _raid_chunksize -_remaining_bytes;
- else // if ( i > _this_block )
- _seek_vector[i] = _rounds;
- }
- break;
- case MY_SEEK_END:
- if (_size==RAID_SIZE_UNKNOWN) // We don't know table size yet
- {
- uint i;
- _position = 0;
- for (i = 0; i < _raid_chunks ; i++ )
- {
- my_off_t newpos = my_seek(_fd_vector[i], 0L, MY_SEEK_END, MyFlags);
- if (newpos == MY_FILEPOS_ERROR)
- DBUG_RETURN (MY_FILEPOS_ERROR);
- _seek_vector[i]=RAID_SEEK_DONE;
- _position += newpos;
- }
- _size=_position;
- }
- else if (_position != _size) // Aren't we also already in the end?
- {
- uint i;
- off_t _rounds;
- _position = _size;
- Calculate();
- _rounds = _total_block / _raid_chunks; // INT() assumed
- _rounds*= _raid_chunksize;
- for (i = 0; i < _raid_chunks ; i++ )
- if ( i < _this_block )
- _seek_vector[i] = _rounds + _raid_chunksize;
- else if ( i == _this_block )
- _seek_vector[i] = _rounds + _raid_chunksize - _remaining_bytes;
- else // if ( i > _this_block )
- _seek_vector[i] = _rounds;
- _position=_size;
- }
- }
- DBUG_RETURN(_position);
-}
-
-
-my_off_t RaidFd::
-Tell(myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Tell");
- DBUG_PRINT("enter",("MyFlags: %d _position: %lu",
- MyFlags, (ulong) _position));
- DBUG_RETURN(_position);
-}
-
-int RaidFd::
-Chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
-{
- DBUG_ENTER("RaidFd::Chsize");
- DBUG_PRINT("enter",("Fd: %d newlength: %lu MyFlags: %d",
- fd, (ulong) newlength, MyFlags));
- _position = newlength;
- Calculate();
- uint _rounds = _total_block / _raid_chunks; // INT() assumed
- for (uint i = 0; i < _raid_chunks ; i++ )
- {
- int newpos;
- if ( i < _this_block )
- newpos = my_chsize(_fd_vector[i],
- _this_block * _raid_chunksize + (_rounds + 1) *
- _raid_chunksize, filler, MyFlags);
- else if ( i == _this_block )
- newpos = my_chsize(_fd_vector[i],
- _this_block * _raid_chunksize + _rounds *
- _raid_chunksize + (newlength % _raid_chunksize),
- filler, MyFlags);
- else // this means: i > _this_block
- newpos = my_chsize(_fd_vector[i],
- _this_block * _raid_chunksize + _rounds *
- _raid_chunksize, filler, MyFlags);
- if (newpos)
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-}
-
-
-int RaidFd::
-Fstat(int fd, MY_STAT *stat_area, myf MyFlags )
-{
- DBUG_ENTER("RaidFd::Fstat");
- DBUG_PRINT("enter",("fd: %d MyFlags: %d",fd,MyFlags));
- uint i;
- int error=0;
- MY_STAT status;
- stat_area->st_size=0;
- stat_area->st_mtime=0;
- stat_area->st_atime=0;
- stat_area->st_ctime=0;
-
- for(i=0 ; i < _raid_chunks ; i++)
- {
- if (my_fstat(_fd_vector[i],&status,MyFlags))
- error=1;
- stat_area->st_size+=status.st_size;
- set_if_bigger(stat_area->st_mtime,status.st_mtime);
- set_if_bigger(stat_area->st_atime,status.st_atime);
- set_if_bigger(stat_area->st_ctime,status.st_ctime);
- }
- DBUG_RETURN(error);
-}
-
-#endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */
diff --git a/mysys/raid2.c b/mysys/raid2.c
deleted file mode 100644
index 4feace7410f..00000000000
--- a/mysys/raid2.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* 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 */
-
-/*
- RAID support for MySQL. For full comments, check raid.cc
- This is in a separate file to not cause problems on OS that can't
- put C++ files in archives.
-*/
-
-#include "mysys_priv.h"
-
-const char *raid_type_string[]={"none","striped"};
-
-const char *my_raid_type(int raid_type)
-{
- return raid_type_string[raid_type];
-}
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
index a7d8f372151..7a2f448b2dc 100644
--- a/mysys/safemalloc.c
+++ b/mysys/safemalloc.c
@@ -51,7 +51,7 @@
(equivalent to realloc())
FREE( pPtr ) Free memory allocated by NEW
(equivalent to free())
- TERMINATE(file) End system, report errors and stats on file
+ 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 )
@@ -82,7 +82,7 @@ static int sf_malloc_tampered= 0;
/* Static functions prototypes */
-static int check_ptr(const char *where, byte *ptr, const char *sFile,
+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);
@@ -119,12 +119,12 @@ static int _checkchunk(struct st_irem *pRec, const char *sFile, uint uLine);
/* Allocate some memory. */
-gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags)
+void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
{
struct st_irem *irem;
- char *data;
+ uchar *data;
DBUG_ENTER("_mymalloc");
- DBUG_PRINT("enter",("Size: %u",size));
+ DBUG_PRINT("enter",("Size: %lu", (ulong) size));
if (!sf_malloc_quick)
(void) _sanity (filename, lineno);
@@ -151,8 +151,8 @@ gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags)
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 %d byte (%ldk), memory in use: %ld bytes (%ldk)",
- size, (size + 1023L) / 1024L,
+ sprintf(buff,"needed %u byte (%ldk), memory in use: %ld bytes (%ldk)",
+ (uint) size, (uint) (size + 1023L) / 1024L,
sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / 1024L);
my_message(EE_OUTOFMEMORY, buff, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH));
}
@@ -160,18 +160,18 @@ gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags)
sf_malloc_max_memory,lineno, filename));
if (MyFlags & MY_FAE)
exit(1);
- DBUG_RETURN ((gptr) 0);
+ DBUG_RETURN ((void*) 0);
}
/* Fill up the structure */
- data= (((char*) irem) + ALIGN_SIZE(sizeof(struct st_irem)) +
+ 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= (my_string) filename;
+ irem->filename= (char *) filename;
irem->linenum= lineno;
irem->datasize= size;
irem->prev= NULL;
@@ -198,7 +198,7 @@ gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags)
sf_min_adress= data;
if (sf_max_adress < data)
sf_max_adress= data;
- DBUG_RETURN ((gptr) data);
+ DBUG_RETURN((void*) data);
}
@@ -207,8 +207,8 @@ gptr _mymalloc(uint size, const char *filename, uint lineno, myf MyFlags)
Free then old memoryblock
*/
-gptr _myrealloc(register gptr ptr, register uint size,
- const char *filename, uint lineno, myf MyFlags)
+void *_myrealloc(register void *ptr, register size_t size,
+ const char *filename, uint lineno, myf MyFlags)
{
struct st_irem *irem;
char *data;
@@ -220,8 +220,8 @@ gptr _myrealloc(register gptr ptr, register uint size,
if (!sf_malloc_quick)
(void) _sanity (filename, lineno);
- if (check_ptr("Reallocating", (byte*) ptr, filename, lineno))
- DBUG_RETURN((gptr) NULL);
+ 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);
@@ -232,13 +232,13 @@ gptr _myrealloc(register gptr ptr, register uint size,
DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
lineno, filename));
(void) fflush(stderr);
- DBUG_RETURN((gptr) NULL);
+ 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((byte*) data, ptr, (size_t) size); /* Copy old data */
+ memcpy((uchar*) data, ptr, (size_t) size); /* Copy old data */
_myfree(ptr, filename, lineno, 0); /* Free not needed area */
}
else
@@ -254,7 +254,7 @@ gptr _myrealloc(register gptr ptr, register uint size,
/* Deallocate some memory. */
-void _myfree(gptr ptr, const char *filename, uint lineno, myf myflags)
+void _myfree(void *ptr, const char *filename, uint lineno, myf myflags)
{
struct st_irem *irem;
DBUG_ENTER("_myfree");
@@ -264,7 +264,7 @@ void _myfree(gptr ptr, const char *filename, uint lineno, myf myflags)
(void) _sanity (filename, lineno);
if ((!ptr && (myflags & MY_ALLOW_ZERO_PTR)) ||
- check_ptr("Freeing",(byte*) ptr,filename,lineno))
+ check_ptr("Freeing",(uchar*) ptr,filename,lineno))
DBUG_VOID_RETURN;
/* Calculate the address of the remember structure */
@@ -316,7 +316,7 @@ void _myfree(gptr ptr, const char *filename, uint lineno, myf myflags)
/* Check if we have a wrong pointer */
-static int check_ptr(const char *where, byte *ptr, const char *filename,
+static int check_ptr(const char *where, uchar *ptr, const char *filename,
uint lineno)
{
if (!ptr)
@@ -352,12 +352,15 @@ static int check_ptr(const char *where, byte *ptr, const char *filename,
/*
- TERMINATE(FILE *file)
- Report on all the memory pieces that have not been
- free'ed as well as the statistics.
+ 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)
+void TERMINATE(FILE *file, uint flag)
{
struct st_irem *irem;
DBUG_ENTER("TERMINATE");
@@ -373,8 +376,7 @@ void TERMINATE(FILE *file)
{
if (file)
{
- fprintf(file, "Warning: Not freed memory segments: %u\n",
- sf_malloc_count);
+ 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));
@@ -414,7 +416,7 @@ void TERMINATE(FILE *file)
}
}
/* Report the memory usage statistics */
- if (file)
+ if (file && flag)
{
fprintf(file, "Maximum memory usage: %ld bytes (%ldk)\n",
sf_malloc_max_memory, (sf_malloc_max_memory + 1023L) / 1024L);
@@ -503,12 +505,12 @@ int _sanity(const char *filename, uint lineno)
/* malloc and copy */
-gptr _my_memdup(const byte *from, uint length, const char *filename,
- uint lineno, myf MyFlags)
+void *_my_memdup(const void *from, size_t length, const char *filename,
+ uint lineno, myf MyFlags)
{
- gptr ptr;
- if ((ptr=_mymalloc(length,filename,lineno,MyFlags)) != 0)
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ void *ptr;
+ if ((ptr= _mymalloc(length,filename,lineno,MyFlags)) != 0)
+ memcpy(ptr, from, length);
return(ptr);
} /*_my_memdup */
@@ -516,23 +518,23 @@ gptr _my_memdup(const byte *from, uint length, const char *filename,
char *_my_strdup(const char *from, const char *filename, uint lineno,
myf MyFlags)
{
- gptr ptr;
- uint length=(uint) strlen(from)+1;
- if ((ptr=_mymalloc(length,filename,lineno,MyFlags)) != 0)
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
- return((char*) ptr);
+ 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_strdup_with_length(const char *from, uint length,
- const char *filename, uint lineno,
- myf MyFlags)
+char *_my_strndup(const char *from, size_t length,
+ const char *filename, uint lineno,
+ myf MyFlags)
{
- gptr ptr;
- if ((ptr=_mymalloc(length+1,filename,lineno,MyFlags)) != 0)
+ char *ptr;
+ if ((ptr= (char*) _mymalloc(length+1,filename,lineno,MyFlags)) != 0)
{
- memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ memcpy((uchar*) ptr, (uchar*) from, (size_t) length);
ptr[length]=0;
}
- return((char *) ptr);
+ return(ptr);
}
diff --git a/mysys/string.c b/mysys/string.c
index df78f2b98b5..b234a589406 100644
--- a/mysys/string.c
+++ b/mysys/string.c
@@ -23,7 +23,7 @@
#include <m_string.h>
my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
- uint init_alloc, uint alloc_increment)
+ size_t init_alloc, size_t alloc_increment)
{
uint length;
DBUG_ENTER("init_dynamic_string");
@@ -31,7 +31,7 @@ my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
if (!alloc_increment)
alloc_increment=128;
length=1;
- if (init_str && (length= (uint) strlen(init_str)+1) < init_alloc)
+ if (init_str && (length= strlen(init_str)+1) < init_alloc)
init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
if (!init_alloc)
init_alloc=alloc_increment;
@@ -72,7 +72,7 @@ my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
}
-my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size)
+my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size)
{
DBUG_ENTER("dynstr_realloc");
@@ -95,7 +95,7 @@ my_bool dynstr_append(DYNAMIC_STRING *str, const char *append)
my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
- uint length)
+ size_t length)
{
char *new_ptr;
if (str->length+length >= str->max_length)
@@ -115,19 +115,29 @@ my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append,
}
-/** Concatenates any number of strings, escapes any OS quote in the result then
- * surround the whole affair in another set of quotes which is finally appended
- * to specified DYNAMIC_STRING. This function is especially useful when
- * building strings to be executed with the system() function.
- * @param str Dynamic String which will have addtional strings appended.
- * @param append String to be appended.
- * @param ... Optional. Additional string(s) to be appended.
- *
- * @note The final argument in the list must be NullS even if no additional
- * options are passed.
- *
- * @return True = Success.
- */
+my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n)
+{
+ str->length-=n;
+ str->str[str->length]= '\0';
+ return FALSE;
+}
+
+/*
+ Concatenates any number of strings, escapes any OS quote in the result then
+ surround the whole affair in another set of quotes which is finally appended
+ to specified DYNAMIC_STRING. This function is especially useful when
+ building strings to be executed with the system() function.
+
+ @param str Dynamic String which will have addtional strings appended.
+ @param append String to be appended.
+ @param ... Optional. Additional string(s) to be appended.
+
+ @note The final argument in the list must be NullS even if no additional
+ options are passed.
+
+ @return True = Success.
+*/
+
my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, ...)
{
#ifdef __WIN__
diff --git a/mysys/test_dir.c b/mysys/test_dir.c
index f1e4987371b..54e6c99e21e 100644
--- a/mysys/test_dir.c
+++ b/mysys/test_dir.c
@@ -15,7 +15,6 @@
/* TODO: Test all functions */
-#define USES_TYPES
#include "mysys_priv.h"
#include "my_dir.h"
diff --git a/mysys/testhash.c b/mysys/testhash.c
index fd2bc73b2ae..2add2ebd2d7 100644
--- a/mysys/testhash.c
+++ b/mysys/testhash.c
@@ -38,11 +38,11 @@ my_bool hash_check(HASH *hash);
void free_record(void *record);
-static byte *hash2_key(const byte *rec,uint *length,
+static uchar *hash2_key(const uchar *rec,uint *length,
my_bool not_used __attribute__((unused)))
{
*length=(uint) (uchar) rec[reclength-1];
- return (byte*) rec;
+ return (uchar*) rec;
}
/* main program */
@@ -196,7 +196,7 @@ static int do_test()
pos=0;
while ((recpos=hash_element(&hash,0)))
{
- record=(byte*) my_malloc(reclength,MYF(MY_FAE));
+ record=(uchar*) my_malloc(reclength,MYF(MY_FAE));
memcpy(record,recpos,reclength);
record[reclength-1]=rnd(5)+1;
if (my_hash_insert(&hash2,record))
@@ -249,7 +249,6 @@ err:
static int get_options(int argc, char **argv)
{
char *pos,*progname;
- DEBUGGER_OFF;
progname= argv[0];
@@ -269,7 +268,6 @@ static int get_options(int argc, char **argv)
printf("Usage: %s [-?ABIKLWv] [-m#] [-t#]\n",progname);
exit(0);
case '#':
- DEBUGGER_ON;
DBUG_PUSH (++pos);
break;
}
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
index d11883a4ea4..afa5aadece7 100644
--- a/mysys/thr_alarm.c
+++ b/mysys/thr_alarm.c
@@ -14,8 +14,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* To avoid problems with alarms in debug code, we disable DBUG here */
-#undef DBUG_OFF
-#define DBUG_OFF
+#define FORCE_DBUG_OFF
#include <my_global.h>
#if defined(THREAD) && !defined(DONT_USE_THR_ALARM)
@@ -39,10 +38,10 @@ uint thr_client_alarm;
static int alarm_aborted=1; /* No alarm thread */
my_bool thr_alarm_inited= 0;
volatile my_bool alarm_thread_running= 0;
-
+time_t next_alarm_expire_time= ~ (time_t) 0;
static sig_handler process_alarm_part2(int sig);
-#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
+#if !defined(__WIN__)
static pthread_mutex_t LOCK_alarm;
static pthread_cond_t COND_alarm;
@@ -61,7 +60,7 @@ static void *alarm_handler(void *arg);
static sig_handler thread_alarm(int sig __attribute__((unused)));
static int compare_ulong(void *not_used __attribute__((unused)),
- byte *a_ptr,byte* b_ptr)
+ uchar *a_ptr,uchar* b_ptr)
{
ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
return (a < b) ? -1 : (a == b) ? 0 : 1;
@@ -72,6 +71,7 @@ void init_thr_alarm(uint max_alarms)
sigset_t s;
DBUG_ENTER("init_thr_alarm");
alarm_aborted=0;
+ next_alarm_expire_time= ~ (time_t) 0;
init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
compare_ulong,NullS);
sigfillset(&full_signal_set); /* Neaded to block signals */
@@ -151,21 +151,28 @@ void resize_thr_alarm(uint max_alarms)
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
{
- ulong now;
+ time_t now;
+#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
+#endif
my_bool reschedule;
+ struct st_my_thread_var *current_my_thread_var= my_thread_var;
DBUG_ENTER("thr_alarm");
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
- now=(ulong) time((time_t*) 0);
+ now= my_time(0);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+#endif
pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
if (alarm_aborted > 0)
{ /* No signal thread */
DBUG_PRINT("info", ("alarm aborted"));
*alrm= 0; /* No alarm */
pthread_mutex_unlock(&LOCK_alarm);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
DBUG_RETURN(1);
}
if (alarm_aborted < 0)
@@ -179,14 +186,14 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
fprintf(stderr,"Warning: thr_alarm queue is full\n");
*alrm= 0; /* No alarm */
pthread_mutex_unlock(&LOCK_alarm);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
DBUG_RETURN(1);
}
max_used_alarms=alarm_queue.elements+1;
}
- reschedule= (!alarm_queue.elements ||
- (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) >
- (int) sec);
+ reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
if (!alarm_data)
{
if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
@@ -194,7 +201,9 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
DBUG_PRINT("info", ("failed my_malloc()"));
*alrm= 0; /* No alarm */
pthread_mutex_unlock(&LOCK_alarm);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
DBUG_RETURN(1);
}
alarm_data->malloced=1;
@@ -203,20 +212,26 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
alarm_data->malloced=0;
alarm_data->expire_time=now+sec;
alarm_data->alarmed=0;
- alarm_data->thread=pthread_self();
- queue_insert(&alarm_queue,(byte*) alarm_data);
+ alarm_data->thread= current_my_thread_var->pthread_self;
+ alarm_data->thread_id= current_my_thread_var->id;
+ queue_insert(&alarm_queue,(uchar*) alarm_data);
/* Reschedule alarm if the current one has more than sec left */
if (reschedule)
{
DBUG_PRINT("info", ("reschedule"));
if (pthread_equal(pthread_self(),alarm_thread))
+ {
alarm(sec); /* purecov: inspected */
+ next_alarm_expire_time= now + sec;
+ }
else
reschedule_alarms(); /* Reschedule alarms */
}
pthread_mutex_unlock(&LOCK_alarm);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
(*alrm)= &alarm_data->alarmed;
DBUG_RETURN(0);
}
@@ -229,21 +244,25 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
void thr_end_alarm(thr_alarm_t *alarmed)
{
ALARM *alarm_data;
+#ifndef USE_ONE_SIGNAL_HAND
sigset_t old_mask;
+#endif
uint i, found=0;
DBUG_ENTER("thr_end_alarm");
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+#endif
pthread_mutex_lock(&LOCK_alarm);
- alarm_data= (ALARM*) ((byte*) *alarmed - offsetof(ALARM,alarmed));
+ alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
for (i=0 ; i < alarm_queue.elements ; i++)
{
if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
{
queue_remove(&alarm_queue,i),MYF(0);
if (alarm_data->malloced)
- my_free((gptr) alarm_data,MYF(0));
+ my_free((uchar*) alarm_data,MYF(0));
found++;
#ifdef DBUG_OFF
break;
@@ -260,7 +279,9 @@ void thr_end_alarm(thr_alarm_t *alarmed)
(long) *alarmed));
}
pthread_mutex_unlock(&LOCK_alarm);
+#ifndef USE_ONE_SIGNAL_HAND
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
DBUG_VOID_RETURN;
}
@@ -350,7 +371,7 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
}
else
{
- ulong now=(ulong) time((time_t*) 0);
+ ulong now=(ulong) my_time(0);
ulong next=now+10-(now%10);
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
{
@@ -379,10 +400,18 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused)))
alarm(0); /* Remove old alarm */
#endif
alarm((uint) (alarm_data->expire_time-now));
+ next_alarm_expire_time= alarm_data->expire_time;
}
#endif
}
}
+ else
+ {
+ /*
+ Ensure that next time we call thr_alarm(), we will schedule a new alarm
+ */
+ next_alarm_expire_time= ~(time_t) 0;
+ }
DBUG_VOID_RETURN;
}
@@ -451,7 +480,7 @@ void end_thr_alarm(my_bool free_structures)
Remove another thread from the alarm
*/
-void thr_alarm_kill(pthread_t thread_id)
+void thr_alarm_kill(my_thread_id thread_id)
{
uint i;
if (alarm_aborted)
@@ -459,12 +488,11 @@ void thr_alarm_kill(pthread_t thread_id)
pthread_mutex_lock(&LOCK_alarm);
for (i=0 ; i < alarm_queue.elements ; i++)
{
- if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
- thread_id))
+ if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
{
ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
tmp->expire_time=0;
- queue_insert(&alarm_queue,(byte*) tmp);
+ queue_insert(&alarm_queue,(uchar*) tmp);
reschedule_alarms();
break;
}
@@ -480,7 +508,7 @@ void thr_alarm_info(ALARM_INFO *info)
info->max_used_alarms= max_used_alarms;
if ((info->active_alarms= alarm_queue.elements))
{
- ulong now=(ulong) time((time_t*) 0);
+ ulong now=(ulong) my_time(0);
long time_diff;
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
time_diff= (long) (alarm_data->expire_time - now);
@@ -528,7 +556,7 @@ static void *alarm_handler(void *arg __attribute__((unused)))
{
if (alarm_queue.elements)
{
- ulong sleep_time,now=time((time_t*) 0);
+ ulong sleep_time,now= my_time(0);
if (alarm_aborted)
sleep_time=now+1;
else
@@ -537,6 +565,7 @@ static void *alarm_handler(void *arg __attribute__((unused)))
{
abstime.tv_sec=sleep_time;
abstime.tv_nsec=0;
+ next_alarm_expire_time= sleep_time;
if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
error != ETIME && error != ETIMEDOUT)
{
@@ -549,12 +578,16 @@ static void *alarm_handler(void *arg __attribute__((unused)))
}
else if (alarm_aborted == -1)
break;
- else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
+ else
{
+ next_alarm_expire_time= ~ (time_t) 0;
+ if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
+ {
#ifdef MAIN
- printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
- error,errno);
+ printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
+ error,errno);
#endif
+ }
}
process_alarm(0);
}
@@ -568,151 +601,12 @@ static void *alarm_handler(void *arg __attribute__((unused)))
#endif /* USE_ALARM_THREAD */
/*****************************************************************************
- thr_alarm for OS/2
-*****************************************************************************/
-
-#elif defined(__EMX__) || defined(OS2)
-
-#define INCL_BASE
-#define INCL_NOPMAPI
-#include <os2.h>
-
-static pthread_mutex_t LOCK_alarm;
-static sigset_t full_signal_set;
-static QUEUE alarm_queue;
-pthread_t alarm_thread;
-
-#ifdef USE_ALARM_THREAD
-static pthread_cond_t COND_alarm;
-static void *alarm_handler(void *arg);
-#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
-#else
-#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
-#endif
-
-sig_handler process_alarm(int sig __attribute__((unused)))
-{
- sigset_t old_mask;
- ALARM *alarm_data;
- DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
-}
-
-
-/*
- Remove another thread from the alarm
-*/
-
-void thr_alarm_kill(pthread_t thread_id)
-{
- uint i;
-
- pthread_mutex_lock(&LOCK_alarm);
- for (i=0 ; i < alarm_queue.elements ; i++)
- {
- if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
- thread_id))
- {
- ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
- tmp->expire_time=0;
- queue_insert(&alarm_queue,(byte*) tmp);
- reschedule_alarms();
- break;
- }
- }
- pthread_mutex_unlock(&LOCK_alarm);
-}
-
-bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
-{
- APIRET rc;
- if (alarm_aborted)
- {
- alarm->alarmed.crono=0;
- alarm->alarmed.event=0;
- return 1;
- }
- if (rc = DosCreateEventSem(NULL,(HEV *) &alarm->alarmed.event,
- DC_SEM_SHARED,FALSE))
- {
- printf("Error creating event semaphore! [%d] \n",rc);
- alarm->alarmed.crono=0;
- alarm->alarmed.event=0;
- return 1;
- }
- if (rc = DosAsyncTimer((long) sec*1000L, (HSEM) alarm->alarmed.event,
- (HTIMER *) &alarm->alarmed.crono))
- {
- printf("Error starting async timer! [%d] \n",rc);
- DosCloseEventSem((HEV) alarm->alarmed.event);
- alarm->alarmed.crono=0;
- alarm->alarmed.event=0;
- return 1;
- } /* endif */
- (*alrm)= &alarm->alarmed;
- return 1;
-}
-
-
-bool thr_got_alarm(thr_alarm_t *alrm_ptr)
-{
- thr_alarm_t alrm= *alrm_ptr;
- APIRET rc;
-
- if (alrm->crono)
- {
- rc = DosWaitEventSem((HEV) alrm->event, SEM_IMMEDIATE_RETURN);
- if (rc == 0) {
- DosCloseEventSem((HEV) alrm->event);
- alrm->crono = 0;
- alrm->event = 0;
- } /* endif */
- }
- return !alrm->crono || alarm_aborted;
-}
-
-
-void thr_end_alarm(thr_alarm_t *alrm_ptr)
-{
- thr_alarm_t alrm= *alrm_ptr;
- if (alrm->crono)
- {
- DosStopTimer((HTIMER) alrm->crono);
- DosCloseEventSem((HEV) alrm->event);
- alrm->crono = 0;
- alrm->event = 0;
- }
-}
-
-void end_thr_alarm(my_bool free_structures)
-{
- DBUG_ENTER("end_thr_alarm");
- alarm_aborted=1; /* No more alarms */
- DBUG_VOID_RETURN;
-}
-
-void init_thr_alarm(uint max_alarm)
-{
- DBUG_ENTER("init_thr_alarm");
- alarm_aborted=0; /* Yes, Gimmie alarms */
- DBUG_VOID_RETURN;
-}
-
-void thr_alarm_info(ALARM_INFO *info)
-{
- bzero((char*) info, sizeof(*info));
-}
-
-void resize_thr_alarm(uint max_alarms)
-{
-}
-
-/*****************************************************************************
thr_alarm for win95
*****************************************************************************/
#else /* __WIN__ */
-void thr_alarm_kill(pthread_t thread_id)
+void thr_alarm_kill(my_thread_id thread_id)
{
/* Can't do this yet */
}
@@ -824,7 +718,7 @@ static void *test_thread(void *arg)
for (i=1 ; i <= 10 ; i++)
{
wait_time=param ? 11-i : i;
- start_time=time((time_t*) 0);
+ start_time= my_time(0);
if (thr_alarm(&got_alarm,wait_time,0))
{
printf("Thread: %s Alarms aborted\n",my_thread_name());
@@ -886,7 +780,7 @@ static void *test_thread(void *arg)
}
}
printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
- (int) (time((time_t*) 0)-start_time), wait_time); fflush(stdout);
+ (int) (my_time(0)-start_time), wait_time); fflush(stdout);
thr_end_alarm(&got_alarm);
fflush(stdout);
}
@@ -894,7 +788,7 @@ static void *test_thread(void *arg)
thread_count--;
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
pthread_mutex_unlock(&LOCK_thread_count);
- free((gptr) arg);
+ free((uchar*) arg);
return 0;
}
@@ -906,10 +800,8 @@ static sig_handler print_signal_warning(int sig)
#ifdef DONT_REMEMBER_SIGNAL
my_sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
-#ifndef OS2
if (sig == SIGALRM)
alarm(2); /* reschedule alarm */
-#endif
}
#endif /* USE_ONE_SIGNAL_HAND */
@@ -926,7 +818,6 @@ static void *signal_hand(void *arg __attribute__((unused)))
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
pthread_mutex_unlock(&LOCK_thread_count);
-#ifndef OS2
sigemptyset(&set); /* Catch all signals */
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
@@ -941,7 +832,6 @@ static void *signal_hand(void *arg __attribute__((unused)))
#else
puts("Starting signal handling thread");
#endif
-#endif /* OS2 */
printf("server alarm: %d thread alarm: %d\n",
THR_SERVER_ALARM, thr_client_alarm);
DBUG_PRINT("info",("Starting signal and alarm handling thread"));
@@ -964,9 +854,7 @@ static void *signal_hand(void *arg __attribute__((unused)))
case SIGINT:
case SIGQUIT:
case SIGTERM:
-#ifndef OS2
case SIGHUP:
-#endif
printf("Aborting nicely\n");
end_thr_alarm(0);
break;
@@ -976,13 +864,11 @@ static void *signal_hand(void *arg __attribute__((unused)))
exit(1);
return 0; /* Keep some compilers happy */
#endif
-#ifndef OS2
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
process_alarm(sig);
break;
#endif
-#endif /* OS2 */
}
}
}
@@ -998,13 +884,13 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
MY_INIT(argv[0]);
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ {
DBUG_PUSH(argv[1]+2);
-
+ }
pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_thread_count,NULL);
/* Start a alarm handling thread */
-#ifndef OS2
sigemptyset(&set);
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
@@ -1022,7 +908,6 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
sigaddset(&set, thr_client_alarm);
VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
#endif
-#endif /* OS2 */
pthread_attr_init(&thr_attr);
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 02c9f08c946..a81ed925562 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -71,7 +71,7 @@ multiple read locks.
*/
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
-#define DBUG_OFF
+#define FORCE_DBUG_OFF
#endif
#include "mysys_priv.h"
@@ -343,8 +343,9 @@ void thr_lock_delete(THR_LOCK *lock)
void thr_lock_info_init(THR_LOCK_INFO *info)
{
- info->thread= pthread_self();
- info->thread_id= my_thread_id(); /* for debugging */
+ struct st_my_thread_var *tmp= my_thread_var;
+ info->thread= tmp->pthread_self;
+ info->thread_id= tmp->id;
info->n_cursors= 0;
}
@@ -489,7 +490,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
data->type=lock_type;
data->owner= owner; /* Must be reset ! */
VOID(pthread_mutex_lock(&lock->mutex));
- DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx type: %d",
+ DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
(long) data, data->owner->info->thread_id,
(long) lock, (int) lock_type));
check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
@@ -508,7 +509,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
and the read lock is not TL_READ_NO_INSERT
*/
- DBUG_PRINT("lock",("write locked by thread: %ld",
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx",
lock->write.data->owner->info->thread_id));
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
(lock->write.data->type <= TL_WRITE_DELAYED &&
@@ -630,8 +631,10 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
- DBUG_PRINT("lock",("write locked by thread: %ld",
+ /* purecov: begin inspected */
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx",
lock->write.data->owner->info->thread_id));
+ /* purecov: end */
}
else
{
@@ -666,7 +669,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
goto end;
}
}
- DBUG_PRINT("lock",("write locked by thread: %ld type: %d",
+ DBUG_PRINT("lock",("write locked by thread: 0x%lx type: %d",
lock->read.data->owner->info->thread_id, data->type));
}
wait_queue= &lock->write_wait;
@@ -728,8 +731,10 @@ static inline void free_all_read_locks(THR_LOCK *lock,
}
lock->read_no_write_count++;
}
- DBUG_PRINT("lock",("giving read lock to thread: %ld",
+ /* purecov: begin inspected */
+ DBUG_PRINT("lock",("giving read lock to thread: 0x%lx",
data->owner->info->thread_id));
+ /* purecov: end */
data->cond=0; /* Mark thread free */
VOID(pthread_cond_signal(cond));
} while ((data=data->next));
@@ -746,7 +751,7 @@ void thr_unlock(THR_LOCK_DATA *data)
THR_LOCK *lock=data->lock;
enum thr_lock_type lock_type=data->type;
DBUG_ENTER("thr_unlock");
- DBUG_PRINT("lock",("data: 0x%lx thread: %ld lock: 0x%lx",
+ DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx",
(long) data, data->owner->info->thread_id, (long) lock));
pthread_mutex_lock(&lock->mutex);
check_locks(lock,"start of release lock",0);
@@ -834,8 +839,10 @@ static void wake_up_waiters(THR_LOCK *lock)
if (data->type == TL_WRITE_CONCURRENT_INSERT &&
(*lock->check_status)(data->status_param))
data->type=TL_WRITE; /* Upgrade lock */
- DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld",
+ /* purecov: begin inspected */
+ DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%lx",
data->type, data->owner->info->thread_id));
+ /* purecov: end */
{
pthread_cond_t *cond=data->cond;
data->cond=0; /* Mark thread free */
@@ -915,7 +922,7 @@ end:
*/
-#define LOCK_CMP(A,B) ((byte*) (A->lock) - (uint) ((A)->type) < (byte*) (B->lock)- (uint) ((B)->type))
+#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
static void sort_locks(THR_LOCK_DATA **data,uint count)
{
@@ -1029,7 +1036,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
thr_unlock(*pos);
else
{
- DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: %ld lock: 0x%lx",
+ DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
(long) *pos, (*pos)->owner->info->thread_id,
(long) (*pos)->lock));
}
@@ -1042,7 +1049,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
TL_WRITE_ONLY to abort any new accesses to the lock
*/
-void thr_abort_locks(THR_LOCK *lock)
+void thr_abort_locks(THR_LOCK *lock, bool upgrade_lock)
{
THR_LOCK_DATA *data;
DBUG_ENTER("thr_abort_locks");
@@ -1064,7 +1071,7 @@ void thr_abort_locks(THR_LOCK *lock)
lock->read_wait.last= &lock->read_wait.data;
lock->write_wait.last= &lock->write_wait.data;
lock->read_wait.data=lock->write_wait.data=0;
- if (lock->write.data)
+ if (upgrade_lock && lock->write.data)
lock->write.data->type=TL_WRITE_ONLY;
pthread_mutex_unlock(&lock->mutex);
DBUG_VOID_RETURN;
@@ -1077,7 +1084,7 @@ void thr_abort_locks(THR_LOCK *lock)
This is used to abort all locks for a specific thread
*/
-my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
+my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
{
THR_LOCK_DATA *data;
my_bool found= FALSE;
@@ -1086,7 +1093,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
pthread_mutex_lock(&lock->mutex);
for (data= lock->read_wait.data; data ; data= data->next)
{
- if (pthread_equal(thread, data->owner->info->thread))
+ if (data->owner->info->thread_id == thread_id) /* purecov: tested */
{
DBUG_PRINT("info",("Aborting read-wait lock"));
data->type= TL_UNLOCK; /* Mark killed */
@@ -1103,7 +1110,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
}
for (data= lock->write_wait.data; data ; data= data->next)
{
- if (pthread_equal(thread, data->owner->info->thread))
+ if (data->owner->info->thread_id == thread_id) /* purecov: tested */
{
DBUG_PRINT("info",("Aborting write-wait lock"));
data->type= TL_UNLOCK;
@@ -1123,6 +1130,218 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
}
+/*
+ Downgrade a WRITE_* to a lower WRITE level
+ SYNOPSIS
+ thr_downgrade_write_lock()
+ in_data Lock data of thread downgrading its lock
+ new_lock_type New write lock type
+ RETURN VALUE
+ NONE
+ DESCRIPTION
+ This can be used to downgrade a lock already owned. When the downgrade
+ occurs also other waiters, both readers and writers can be allowed to
+ start.
+ The previous lock is often TL_WRITE_ONLY but can also be
+ TL_WRITE and TL_WRITE_ALLOW_READ. The normal downgrade variants are
+ TL_WRITE_ONLY => TL_WRITE_ALLOW_READ After a short exclusive lock
+ TL_WRITE_ALLOW_READ => TL_WRITE_ALLOW_WRITE After discovering that the
+ operation didn't need such a high lock.
+ TL_WRITE_ONLY => TL_WRITE after a short exclusive lock while holding a
+ write table lock
+ TL_WRITE_ONLY => TL_WRITE_ALLOW_WRITE After a short exclusive lock after
+ already earlier having dongraded lock to TL_WRITE_ALLOW_WRITE
+ The implementation is conservative and rather don't start rather than
+ go on unknown paths to start, the common cases are handled.
+
+ NOTE:
+ In its current implementation it is only allowed to downgrade from
+ TL_WRITE_ONLY. In this case there are no waiters. Thus no wake up
+ logic is required.
+*/
+
+void thr_downgrade_write_lock(THR_LOCK_DATA *in_data,
+ enum thr_lock_type new_lock_type)
+{
+ THR_LOCK *lock=in_data->lock;
+#ifndef DBUG_OFF
+ enum thr_lock_type old_lock_type= in_data->type;
+#endif
+#ifdef TO_BE_REMOVED
+ THR_LOCK_DATA *data, *next;
+ bool start_writers= FALSE;
+ bool start_readers= FALSE;
+#endif
+ DBUG_ENTER("thr_downgrade_write_only_lock");
+
+ pthread_mutex_lock(&lock->mutex);
+ DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY);
+ DBUG_ASSERT(old_lock_type > new_lock_type);
+ in_data->type= new_lock_type;
+ check_locks(lock,"after downgrading lock",0);
+
+#if TO_BE_REMOVED
+ switch (old_lock_type)
+ {
+ case TL_WRITE_ONLY:
+ case TL_WRITE:
+ case TL_WRITE_LOW_PRIORITY:
+ /*
+ Previous lock was exclusive we are now ready to start up most waiting
+ threads.
+ */
+ switch (new_lock_type)
+ {
+ case TL_WRITE_ALLOW_READ:
+ /* Still cannot start WRITE operations. Can only start readers. */
+ start_readers= TRUE;
+ break;
+ case TL_WRITE:
+ case TL_WRITE_LOW_PRIORITY:
+ /*
+ Still cannot start anything, but new requests are no longer
+ aborted.
+ */
+ break;
+ case TL_WRITE_ALLOW_WRITE:
+ /*
+ We can start both writers and readers.
+ */
+ start_writers= TRUE;
+ start_readers= TRUE;
+ break;
+ case TL_WRITE_CONCURRENT_INSERT:
+ case TL_WRITE_DELAYED:
+ /*
+ This routine is not designed for those. Lock will be downgraded
+ but no start of waiters will occur. This is not the optimal but
+ should be a correct behaviour.
+ */
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ break;
+ case TL_WRITE_DELAYED:
+ case TL_WRITE_CONCURRENT_INSERT:
+ /*
+ This routine is not designed for those. Lock will be downgraded
+ but no start of waiters will occur. This is not the optimal but
+ should be a correct behaviour.
+ */
+ break;
+ case TL_WRITE_ALLOW_READ:
+ DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
+ /*
+ Previously writers were not allowed to start, now it is ok to
+ start them again. Readers are already allowed so no reason to
+ handle them.
+ */
+ start_writers= TRUE;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ if (start_writers)
+ {
+ /*
+ At this time the only active writer can be ourselves. Thus we need
+ not worry about that there are other concurrent write operations
+ active on the table. Thus we only need to worry about starting
+ waiting operations.
+ We also only come here with TL_WRITE_ALLOW_WRITE as the new
+ lock type, thus we can start other writers also of the same type.
+ If we find a lock at exclusive level >= TL_WRITE_LOW_PRIORITY we
+ don't start any more operations that would be mean those operations
+ will have to wait for things started afterwards.
+ */
+ DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE);
+ for (data=lock->write_wait.data; data ; data= next)
+ {
+ /*
+ All WRITE requests compatible with new lock type are also
+ started
+ */
+ next= data->next;
+ if (start_writers && data->type == new_lock_type)
+ {
+ pthread_cond_t *cond= data->cond;
+ /*
+ It is ok to start this waiter.
+ Move from being first in wait queue to be last in write queue.
+ */
+ if (((*data->prev)= data->next))
+ data->next->prev= data->prev;
+ else
+ lock->write_wait.last= data->prev;
+ data->prev= lock->write.last;
+ lock->write.last= &data->next;
+ data->next= 0;
+ check_locks(lock, "Started write lock after downgrade",0);
+ data->cond= 0;
+ pthread_cond_signal(cond);
+ }
+ else
+ {
+ /*
+ We found an incompatible lock, we won't start any more write
+ requests to avoid letting writers pass other writers in the
+ queue.
+ */
+ start_writers= FALSE;
+ if (data->type >= TL_WRITE_LOW_PRIORITY)
+ {
+ /*
+ We have an exclusive writer in the queue so we won't start
+ readers either.
+ */
+ start_readers= FALSE;
+ }
+ }
+ }
+ }
+ if (start_readers)
+ {
+ DBUG_ASSERT(new_lock_type == TL_WRITE_ALLOW_WRITE ||
+ new_lock_type == TL_WRITE_ALLOW_READ);
+ /*
+ When we come here we know that the write locks are
+ TL_WRITE_ALLOW_WRITE or TL_WRITE_ALLOW_READ. This means that reads
+ are ok
+ */
+ for (data=lock->read_wait.data; data ; data=next)
+ {
+ next= data->next;
+ /*
+ All reads are ok to start now except TL_READ_NO_INSERT when
+ write lock is TL_WRITE_ALLOW_READ.
+ */
+ if (new_lock_type != TL_WRITE_ALLOW_READ ||
+ data->type != TL_READ_NO_INSERT)
+ {
+ pthread_cond_t *cond= data->cond;
+ if (((*data->prev)= data->next))
+ data->next->prev= data->prev;
+ else
+ lock->read_wait.last= data->prev;
+ data->prev= lock->read.last;
+ lock->read.last= &data->next;
+ data->next= 0;
+
+ if (data->type == TL_READ_NO_INSERT)
+ lock->read_no_write_count++;
+ check_locks(lock, "Started read lock after downgrade",0);
+ data->cond= 0;
+ pthread_cond_signal(cond);
+ }
+ }
+ }
+ check_locks(lock,"after starting waiters after downgrading lock",0);
+#endif
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+}
/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
@@ -1342,6 +1561,10 @@ static void test_get_status(void* param __attribute__((unused)),
{
}
+static void test_update_status(void* param __attribute__((unused)))
+{
+}
+
static void test_copy_status(void* to __attribute__((unused)) ,
void *from __attribute__((unused)))
{
@@ -1401,7 +1624,7 @@ static void *test_thread(void *arg)
thread_count--;
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
pthread_mutex_unlock(&LOCK_thread_count);
- free((gptr) arg);
+ free((uchar*) arg);
return 0;
}
@@ -1434,7 +1657,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
thr_lock_init(locks+i);
locks[i].check_status= test_check_status;
- locks[i].update_status=test_get_status;
+ locks[i].update_status=test_update_status;
locks[i].copy_status= test_copy_status;
locks[i].get_status= test_get_status;
}
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index 425e5fce459..007bae2accf 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -212,7 +212,7 @@ int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
{
fprintf(stderr,
"safe_mutex: Count was %d in thread 0x%lx when locking mutex at %s, line %d\n",
- mp->count-1, my_thread_id(), file, line);
+ mp->count-1, my_thread_dbug_id(), file, line);
fflush(stderr);
abort();
}
@@ -250,7 +250,7 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
{
fprintf(stderr,
"safe_mutex: Count was %d in thread 0x%lx when locking mutex at %s, line %d (error: %d (%d))\n",
- mp->count-1, my_thread_id(), file, line, error, error);
+ mp->count-1, my_thread_dbug_id(), file, line, error, error);
fflush(stderr);
abort();
}
@@ -356,3 +356,80 @@ void safe_mutex_end(FILE *file __attribute__((unused)))
}
#endif /* THREAD && SAFE_MUTEX */
+
+#if defined(THREAD) && defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include <m_string.h>
+
+#include <m_ctype.h>
+#include <hash.h>
+#include <myisampack.h>
+#include <mysys_err.h>
+#include <my_sys.h>
+
+#undef pthread_mutex_t
+#undef pthread_mutex_init
+#undef pthread_mutex_lock
+#undef pthread_mutex_trylock
+#undef pthread_mutex_unlock
+#undef pthread_mutex_destroy
+#undef pthread_cond_wait
+#undef pthread_cond_timedwait
+
+ulong mutex_delay(ulong delayloops)
+{
+ ulong i;
+ volatile ulong j;
+
+ j = 0;
+
+ for (i = 0; i < delayloops * 50; i++)
+ j += i;
+
+ return(j);
+}
+
+#define MY_PTHREAD_FASTMUTEX_SPINS 8
+#define MY_PTHREAD_FASTMUTEX_DELAY 4
+
+int my_pthread_fastmutex_init(my_pthread_fastmutex_t *mp,
+ const pthread_mutexattr_t *attr)
+{
+ static int cpu_count= 0;
+#ifdef _SC_NPROCESSORS_CONF
+ if (!cpu_count && (attr == MY_MUTEX_INIT_FAST))
+ cpu_count= sysconf(_SC_NPROCESSORS_CONF);
+#endif
+
+ if ((cpu_count > 1) && (attr == MY_MUTEX_INIT_FAST))
+ mp->spins= MY_PTHREAD_FASTMUTEX_SPINS;
+ else
+ mp->spins= 0;
+ return pthread_mutex_init(&mp->mutex, attr);
+}
+
+int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp)
+{
+ int res;
+ uint i;
+ uint maxdelay= MY_PTHREAD_FASTMUTEX_DELAY;
+
+ for (i= 0; i < mp->spins; i++)
+ {
+ res= pthread_mutex_trylock(&mp->mutex);
+
+ if (res == 0)
+ return 0;
+
+ if (res != EBUSY)
+ return res;
+
+ mutex_delay(maxdelay);
+ maxdelay += ((double) random() / (double) RAND_MAX) *
+ MY_PTHREAD_FASTMUTEX_DELAY + 1;
+ }
+ return pthread_mutex_lock(&mp->mutex);
+}
+#endif /* defined(THREAD) && defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */
diff --git a/mysys/tree.c b/mysys/tree.c
index 2e6868e0777..ef33f75b7c6 100644
--- a/mysys/tree.c
+++ b/mysys/tree.c
@@ -93,7 +93,7 @@ void init_tree(TREE *tree, ulong default_alloc_size, ulong memory_limit,
if (default_alloc_size < DEFAULT_ALLOC_SIZE)
default_alloc_size= DEFAULT_ALLOC_SIZE;
default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE);
- bzero((gptr) &tree->null_element,sizeof(tree->null_element));
+ bzero((uchar*) &tree->null_element,sizeof(tree->null_element));
tree->root= &tree->null_element;
tree->compare=compare;
tree->size_of_element=size > 0 ? (uint) size : 0;
@@ -247,12 +247,12 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size,
else
{
*((void**) (element+1))= (void*) ((void **) (element+1)+1);
- memcpy((byte*) *((void **) (element+1)),key,
+ memcpy((uchar*) *((void **) (element+1)),key,
(size_t) (key_size-sizeof(void*)));
}
}
else
- memcpy((byte*) element+tree->offset_to_key,key,(size_t) key_size);
+ memcpy((uchar*) element+tree->offset_to_key,key,(size_t) key_size);
element->count=1; /* May give warning in purify */
tree->elements_in_tree++;
rb_insert(tree,parent,element); /* rebalance tree */
@@ -326,7 +326,7 @@ int tree_delete(TREE *tree, void *key, uint key_size, void *custom_arg)
if (tree->free)
(*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
tree->allocated-= sizeof(TREE_ELEMENT) + tree->size_of_element + key_size;
- my_free((gptr) element,MYF(0));
+ my_free((uchar*) element,MYF(0));
tree->elements_in_tree--;
return 0;
}
diff --git a/mysys/trie.c b/mysys/trie.c
new file mode 100644
index 00000000000..5738b9b866b
--- /dev/null
+++ b/mysys/trie.c
@@ -0,0 +1,236 @@
+/* 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 */
+
+/*
+ Implementation of trie and Aho-Corasick automaton.
+ Supports only charsets that can be compared byte-wise.
+
+ TODO:
+ Add character frequencies. Can increase lookup speed
+ up to 30%.
+ Implement character-wise comparision.
+*/
+
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_trie.h>
+#include <my_base.h>
+
+
+/*
+ SYNOPSIS
+ TRIE *trie_init (TRIE *trie, CHARSET_INFO *charset);
+
+ DESCRIPTION
+ Allocates or initializes a `TRIE' object. If `trie' is a `NULL'
+ pointer, the function allocates, initializes, and returns a new
+ object. Otherwise, the object is initialized and the address of
+ the object is returned. If `trie_init()' allocates a new object,
+ it will be freed when `trie_free()' is called.
+
+ RETURN VALUE
+ An initialized `TRIE*' object. `NULL' if there was insufficient
+ memory to allocate a new object.
+*/
+
+TRIE *trie_init (TRIE *trie, CHARSET_INFO *charset)
+{
+ MEM_ROOT mem_root;
+ DBUG_ENTER("trie_init");
+ DBUG_ASSERT(charset);
+ init_alloc_root(&mem_root,
+ (sizeof(TRIE_NODE) * 128) + ALLOC_ROOT_MIN_BLOCK_SIZE,
+ sizeof(TRIE_NODE) * 128);
+ if (! trie)
+ {
+ if (! (trie= (TRIE *)alloc_root(&mem_root, sizeof(TRIE))))
+ {
+ free_root(&mem_root, MYF(0));
+ DBUG_RETURN(NULL);
+ }
+ }
+
+ memcpy(&trie->mem_root, &mem_root, sizeof(MEM_ROOT));
+ trie->root.leaf= 0;
+ trie->root.c= 0;
+ trie->root.next= NULL;
+ trie->root.links= NULL;
+ trie->root.fail= NULL;
+ trie->charset= charset;
+ trie->nnodes= 0;
+ trie->nwords= 0;
+ DBUG_RETURN(trie);
+}
+
+
+/*
+ SYNOPSIS
+ void trie_free (TRIE *trie);
+ trie - valid pointer to `TRIE'
+
+ DESCRIPTION
+ Frees the memory allocated for a `trie'.
+
+ RETURN VALUE
+ None.
+*/
+
+void trie_free (TRIE *trie)
+{
+ MEM_ROOT mem_root;
+ DBUG_ENTER("trie_free");
+ DBUG_ASSERT(trie);
+ memcpy(&mem_root, &trie->mem_root, sizeof(MEM_ROOT));
+ free_root(&mem_root, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ SYNOPSIS
+ my_bool trie_insert (TRIE *trie, const uchar *key, uint keylen);
+ trie - valid pointer to `TRIE'
+ key - valid pointer to key to insert
+ keylen - non-0 key length
+
+ DESCRIPTION
+ Inserts new key into trie.
+
+ RETURN VALUE
+ Upon successful completion, `trie_insert' returns `FALSE'. Otherwise
+ `TRUE' is returned.
+
+ NOTES
+ If this function fails you must assume `trie' is broken.
+ However it can be freed with trie_free().
+*/
+
+my_bool trie_insert (TRIE *trie, const uchar *key, uint keylen)
+{
+ TRIE_NODE *node;
+ TRIE_NODE *next;
+ uchar p;
+ uint k;
+ DBUG_ENTER("trie_insert");
+ DBUG_ASSERT(trie && key && keylen);
+ node= &trie->root;
+ trie->root.fail= NULL;
+ for (k= 0; k < keylen; k++)
+ {
+ p= key[k];
+ for (next= node->links; next; next= next->next)
+ if (next->c == p)
+ break;
+
+ if (! next)
+ {
+ TRIE_NODE *tmp= (TRIE_NODE *)alloc_root(&trie->mem_root,
+ sizeof(TRIE_NODE));
+ if (! tmp)
+ DBUG_RETURN(TRUE);
+ tmp->leaf= 0;
+ tmp->c= p;
+ tmp->links= tmp->fail= tmp->next= NULL;
+ trie->nnodes++;
+ if (! node->links)
+ {
+ node->links= tmp;
+ }
+ else
+ {
+ for (next= node->links; next->next; next= next->next) /* no-op */;
+ next->next= tmp;
+ }
+ node= tmp;
+ }
+ else
+ {
+ node= next;
+ }
+ }
+ node->leaf= keylen;
+ trie->nwords++;
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ SYNOPSIS
+ my_bool trie_prepare (TRIE *trie);
+ trie - valid pointer to `TRIE'
+
+ DESCRIPTION
+ Constructs Aho-Corasick automaton.
+
+ RETURN VALUE
+ Upon successful completion, `trie_prepare' returns `FALSE'. Otherwise
+ `TRUE' is returned.
+*/
+
+my_bool ac_trie_prepare (TRIE *trie)
+{
+ TRIE_NODE **tmp_nodes;
+ TRIE_NODE *node;
+ uint32 fnode= 0;
+ uint32 lnode= 0;
+ DBUG_ENTER("trie_prepare");
+ DBUG_ASSERT(trie);
+
+ tmp_nodes= (TRIE_NODE **)my_malloc(trie->nnodes * sizeof(TRIE_NODE *), MYF(0));
+ if (! tmp_nodes)
+ DBUG_RETURN(TRUE);
+
+ trie->root.fail= &trie->root;
+ for (node= trie->root.links; node; node= node->next)
+ {
+ node->fail= &trie->root;
+ tmp_nodes[lnode++]= node;
+ }
+
+ while (fnode < lnode)
+ {
+ TRIE_NODE *current= (TRIE_NODE *)tmp_nodes[fnode++];
+ for (node= current->links; node; node= node->next)
+ {
+ TRIE_NODE *fail= current->fail;
+ tmp_nodes[lnode++]= node;
+ while (! (node->fail= trie_goto(&trie->root, fail, node->c)))
+ fail= fail->fail;
+ }
+ }
+ my_free((uchar*)tmp_nodes, MYF(0));
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ SYNOPSIS
+ void ac_trie_init (TRIE *trie, AC_TRIE_STATE *state);
+ trie - valid pointer to `TRIE'
+ state - value pointer to `AC_TRIE_STATE'
+
+ DESCRIPTION
+ Initializes `AC_TRIE_STATE' object.
+*/
+
+void ac_trie_init (TRIE *trie, AC_TRIE_STATE *state)
+{
+ DBUG_ENTER("ac_trie_init");
+ DBUG_ASSERT(trie && state);
+ state->trie= trie;
+ state->node= &trie->root;
+ DBUG_VOID_RETURN;
+}
diff --git a/mysys/typelib.c b/mysys/typelib.c
index 4fab6f20493..e745a9fb917 100644
--- a/mysys/typelib.c
+++ b/mysys/typelib.c
@@ -20,6 +20,30 @@
#include <m_ctype.h>
+static const char field_separator=',';
+
+int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option)
+{
+ int res;
+ const char **ptr;
+
+ if ((res= find_type((char *) x, typelib, 2)) <= 0)
+ {
+ ptr= typelib->type_names;
+ if (!*x)
+ fprintf(stderr, "No option given to %s\n", option);
+ else
+ fprintf(stderr, "Unknown option to %s: %s\n", option, x);
+ fprintf(stderr, "Alternatives are: '%s'", *ptr);
+ while (*++ptr)
+ fprintf(stderr, ",'%s'", *ptr);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ return res;
+}
+
+
/*
Search after a string in a list of strings. Endspace in x is not compared.
@@ -31,6 +55,7 @@
If & 1 accept only whole names
If & 2 don't expand if half field
If & 4 allow #number# as type
+ If & 8 use ',' as string terminator
NOTES
If part, uniq field is found and full_name == 0 then x is expanded
@@ -42,10 +67,11 @@
>0 Offset+1 in typelib for matched string
*/
-int find_type(my_string x, TYPELIB *typelib, uint full_name)
+
+int find_type(char *x, const TYPELIB *typelib, uint full_name)
{
int find,pos,findpos;
- reg1 my_string i;
+ reg1 char * i;
reg2 const char *j;
DBUG_ENTER("find_type");
DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) typelib));
@@ -60,16 +86,18 @@ int find_type(my_string x, TYPELIB *typelib, uint full_name)
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{
for (i=x ;
- *i && my_toupper(&my_charset_latin1,*i) ==
+ *i && (!(full_name & 8) || *i != field_separator) &&
+ my_toupper(&my_charset_latin1,*i) ==
my_toupper(&my_charset_latin1,*j) ; i++, j++) ;
if (! *j)
{
while (*i == ' ')
i++; /* skip_end_space */
- if (! *i)
+ if (! *i || ((full_name & 8) && *i == field_separator))
DBUG_RETURN(pos+1);
}
- if (! *i && (!*j || !(full_name & 1)))
+ if ((!*i && (!(full_name & 8) || *i != field_separator)) &&
+ (!*j || !(full_name & 1)))
{
find++;
findpos=pos;
@@ -97,7 +125,7 @@ int find_type(my_string x, TYPELIB *typelib, uint full_name)
/* Get name of type nr 'nr' */
/* Warning first type is 1, 0 = empty field */
-void make_type(register my_string to, register uint nr,
+void make_type(register char * to, register uint nr,
register TYPELIB *typelib)
{
DBUG_ENTER("make_type");
@@ -121,6 +149,50 @@ const char *get_type(TYPELIB *typelib, uint nr)
/*
+ Create an integer value to represent the supplied comma-seperated
+ string where each string in the TYPELIB denotes a bit position.
+
+ SYNOPSIS
+ find_typeset()
+ x string to decompose
+ lib TYPELIB (struct of pointer to values + count)
+ err index (not char position) of string element which was not
+ found or 0 if there was no error
+
+ RETURN
+ a integer representation of the supplied string
+*/
+
+my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err)
+{
+ my_ulonglong result;
+ int find;
+ char *i;
+ DBUG_ENTER("find_set");
+ DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) lib));
+
+ if (!lib->count)
+ {
+ DBUG_PRINT("exit",("no count"));
+ DBUG_RETURN(0);
+ }
+ result= 0;
+ *err= 0;
+ while (*x)
+ {
+ (*err)++;
+ i= x;
+ while (*x && *x != field_separator) x++;
+ if ((find= find_type(i, lib, 2 | 8) - 1) < 0)
+ DBUG_RETURN(0);
+ result|= (ULL(1) << find);
+ }
+ *err= 0;
+ DBUG_RETURN(result);
+} /* find_set */
+
+
+/*
Create a copy of a specified TYPELIB structure.
SYNOPSIS