Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
e69becf1
Commit
e69becf1
authored
Nov 15, 2000
by
monty@narttu.mysql.fi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
changed to use IO_CACHE instead of FILE
parent
7a013339
Changes
24
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
816 additions
and
821 deletions
+816
-821
BitKeeper/etc/logging_ok
BitKeeper/etc/logging_ok
+1
-1
Docs/manual.texi
Docs/manual.texi
+10
-4
client/mysqlimport.c
client/mysqlimport.c
+2
-2
client/sql_string.cc
client/sql_string.cc
+15
-11
client/sql_string.h
client/sql_string.h
+9
-9
include/my_sys.h
include/my_sys.h
+5
-0
mysql.proj
mysql.proj
+0
-0
mysys/Makefile.am
mysys/Makefile.am
+1
-1
mysys/mf_cache.c
mysys/mf_cache.c
+5
-3
mysys/mf_iocache.c
mysys/mf_iocache.c
+27
-16
mysys/my_vsnprintf.c
mysys/my_vsnprintf.c
+33
-58
sql/log.cc
sql/log.cc
+174
-168
sql/log_event.cc
sql/log_event.cc
+126
-175
sql/log_event.h
sql/log_event.h
+31
-32
sql/mf_iocache.cc
sql/mf_iocache.cc
+30
-18
sql/mysqlbinlog.cc
sql/mysqlbinlog.cc
+82
-62
sql/net_pkg.cc
sql/net_pkg.cc
+5
-5
sql/sql_class.cc
sql/sql_class.cc
+11
-2
sql/sql_class.h
sql/sql_class.h
+6
-5
sql/sql_parse.cc
sql/sql_parse.cc
+1
-1
sql/sql_repl.cc
sql/sql_repl.cc
+226
-226
sql/sql_string.cc
sql/sql_string.cc
+15
-11
sql/sql_string.h
sql/sql_string.h
+1
-1
sql/time.cc
sql/time.cc
+0
-10
No files found.
BitKeeper/etc/logging_ok
View file @
e69becf1
monty@
tik.mysql.com
monty@
narttu.mysql.fi
Docs/manual.texi
View file @
e69becf1
...
...
@@ -3610,10 +3610,13 @@ similar system. In the worst case, we may require access to your system
to be able to create a binary distribution.
@item
If you can provide accommodations and pay for traveler fares, you can even
get a @strong{MySQL} developer to visit you and offer you help with your
troubles. Extended login support entitles you to one personal
encounter per year, but we are always very flexible towards our customers!
If you can provide accommodations and pay for traveler fares, you can
even get a @strong{MySQL} developer to visit you and offer you help with
your troubles. Extended login support entitles you to one personal
encounter per year, but we are always very flexible towards our
customers! If the visit takes 16 hours or more, the first 8 hours is
without charge. For the hours above 8 hours, you will be charged with a
rate that is at least 20 % less than our standard rates.
@end itemize
@node Installing, Compatibility, Licensing and Support, Top
...
...
@@ -38367,6 +38370,9 @@ though, so 3.23 is not released as a stable version yet.
@appendixsubsec Changes in release 3.23.28
@itemize @bullet
@item
Changed all log files to use our own IO_CACHE mechanism instead of
FILE:s to avoid OS problems when there is many files open.
@item
Added options @code{--open-files} and @code{--timezone} to @code{safe_mysqld}.
@item
Fixed fatal bug in @code{CREATE TEMPORARY TABLE ...SELECT ...}.
client/mysqlimport.c
View file @
e69becf1
...
...
@@ -25,7 +25,7 @@
** * *
** *************************
*/
#define IMPORT_VERSION "2.
5
"
#define IMPORT_VERSION "2.
6
"
#include <global.h>
#include <my_sys.h>
...
...
@@ -125,7 +125,7 @@ file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
Give the column names in a comma separated list.
\n
\
This is same as giving columns to LOAD DATA INFILE.
\n
\
-C, --compress Use compression in server/client protocol
\n
\
-d, --delete
Deletes first
all rows from table.
\n
\
-d, --delete
First delete
all rows from table.
\n
\
-f, --force Continue even if we get an sql-error.
\n
\
-h, --host=... Connect to host.
\n
\
-i, --ignore If duplicate unique key was found, keep old row.
\n
\
...
...
client/sql_string.cc
View file @
e69becf1
...
...
@@ -95,17 +95,6 @@ bool String::realloc(uint32 alloc_length)
return
FALSE
;
}
#ifdef NOT_NEEDED
bool
String
::
set
(
long
num
)
{
if
(
alloc
(
14
))
return
TRUE
;
str_length
=
(
uint32
)
(
int10_to_str
(
num
,
Ptr
,
-
10
)
-
Ptr
);
return
FALSE
;
}
#endif
bool
String
::
set
(
longlong
num
)
{
if
(
alloc
(
21
))
...
...
@@ -274,6 +263,7 @@ bool String::append(const char *s,uint32 arg_length)
return
FALSE
;
}
#ifdef TO_BE_REMOVED
bool
String
::
append
(
FILE
*
file
,
uint32
arg_length
,
myf
my_flags
)
{
if
(
realloc
(
str_length
+
arg_length
))
...
...
@@ -286,6 +276,20 @@ bool String::append(FILE* file, uint32 arg_length, myf my_flags)
str_length
+=
arg_length
;
return
FALSE
;
}
#endif
bool
String
::
append
(
IO_CACHE
*
file
,
uint32
arg_length
)
{
if
(
realloc
(
str_length
+
arg_length
))
return
TRUE
;
if
(
my_b_read
(
file
,
(
byte
*
)
Ptr
+
str_length
,
arg_length
))
{
shrink
(
str_length
);
return
TRUE
;
}
str_length
+=
arg_length
;
return
FALSE
;
}
uint32
String
::
numchars
()
{
...
...
client/sql_string.h
View file @
e69becf1
...
...
@@ -107,9 +107,9 @@ public:
Alloced_length
=
0
;
my_free
(
Ptr
,
MYF
(
0
));
Ptr
=
0
;
str_length
=
0
;
/* Safety */
}
}
inline
bool
alloc
(
uint32
arg_length
)
{
if
(
arg_length
<
Alloced_length
)
...
...
@@ -152,7 +152,7 @@ public:
bool
copy
(
const
char
*
s
,
uint32
arg_length
);
// Allocate new string
bool
append
(
const
String
&
s
);
bool
append
(
const
char
*
s
,
uint32
arg_length
=
0
);
bool
append
(
FILE
*
file
,
uint32
arg_length
,
myf
my_flags
);
bool
append
(
IO_CACHE
*
file
,
uint32
arg_length
);
int
strstr
(
const
String
&
search
,
uint32
offset
=
0
);
// Returns offset to substring or -1
int
strrstr
(
const
String
&
search
,
uint32
offset
=
0
);
// Returns offset to substring or -1
bool
replace
(
uint32
offset
,
uint32
arg_length
,
const
String
&
to
);
...
...
include/my_sys.h
View file @
e69becf1
...
...
@@ -59,6 +59,7 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_WME 16
/* Write message on error */
#define MY_WAIT_IF_FULL 32
/* Wait and try again if disk full error */
#define MY_RAID 64
/* Support for RAID (not the "Johnson&Johnson"-s one ;) */
#define MY_DONT_CHECK_FILESIZE 128
/* Option to init_io_cache() */
#define MY_LINK_WARNING 32
/* my_redel() gives warning if links */
#define MY_COPYTIME 64
/* my_redel() copys time */
#define MY_HOLD_ORIGINAL_MODES 128
/* my_copy() holds to file modes */
...
...
@@ -505,6 +506,10 @@ extern int my_block_write(IO_CACHE *info, const byte *Buffer,
uint
Count
,
my_off_t
pos
);
extern
int
flush_io_cache
(
IO_CACHE
*
info
);
extern
int
end_io_cache
(
IO_CACHE
*
info
);
extern
uint
my_b_fill
(
IO_CACHE
*
info
);
extern
void
my_b_seek
(
IO_CACHE
*
info
,
my_off_t
pos
);
extern
uint
my_b_gets
(
IO_CACHE
*
info
,
char
*
to
,
uint
max_length
);
extern
uint
my_b_printf
(
IO_CACHE
*
info
,
const
char
*
fmt
,
...);
extern
my_bool
open_cached_file
(
IO_CACHE
*
cache
,
const
char
*
dir
,
const
char
*
prefix
,
uint
cache_size
,
myf
cache_myflags
);
...
...
mysql.proj
View file @
e69becf1
No preview for this file type
mysys/Makefile.am
View file @
e69becf1
...
...
@@ -26,7 +26,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
mf_path.c mf_loadpath.c
\
my_open.c my_create.c my_seek.c my_read.c
\
my_pread.c my_write.c
\
mf_
reccache.c mf_
keycache.c
\
mf_keycache.c
\
mf_iocache.c mf_cache.c mf_tempfile.c
\
my_lock.c mf_brkhant.c my_alarm.c
\
my_malloc.c my_realloc.c my_once.c mulalloc.c
\
...
...
mysys/mf_cache.c
View file @
e69becf1
...
...
@@ -74,7 +74,7 @@ my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
}
my_free
(
cache
->
dir
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
cache
->
prefix
,
MYF
(
MY_ALLOW_ZERO_PTR
));
DBUG_RETURN
(
0
);
DBUG_RETURN
(
1
);
}
/* Create the temporary file */
...
...
@@ -101,10 +101,12 @@ void close_cached_file(IO_CACHE *cache)
DBUG_ENTER
(
"close_cached_file"
);
if
(
my_b_inited
(
cache
))
{
File
file
=
cache
->
file
;
cache
->
file
=
-
1
;
/* Don't flush data */
(
void
)
end_io_cache
(
cache
);
if
(
cache
->
file
>=
0
)
if
(
file
>=
0
)
{
(
void
)
my_close
(
cache
->
file
,
MYF
(
0
));
(
void
)
my_close
(
file
,
MYF
(
0
));
#ifdef CANT_DELETE_OPEN_FILES
if
(
cache
->
file_name
)
{
...
...
mysys/mf_iocache.c
View file @
e69becf1
...
...
@@ -22,10 +22,13 @@
(and get a EOF-error).
Possibly use of asyncronic io.
macros for read and writes for faster io.
Used instead of FILE when reading or writing hole files.
This
shall make mf_rec_cache obsoli
te.
One can change info->pos_in_file to a hig
er value to skip
p bytes in file if
Used instead of FILE when reading or writing
w
hole files.
This
will make mf_rec_cache obsole
te.
One can change info->pos_in_file to a hig
her value to ski
p bytes in file if
also info->rc_pos is set to info->rc_end.
If called through open_cached_file(), then the temporary file will
only be created if a write exeeds the file buffer or if one calls
flush_io_cache().
*/
#define MAP_TO_USE_RAID
...
...
@@ -40,7 +43,7 @@ static void my_aiowait(my_aio_result *result);
/*
** if cachesize == 0 then use default cachesize (from s-file)
** if file == -1 then real_open_cached_file() will be called
to
** if file == -1 then real_open_cached_file() will be called
.
** returns 0 if ok
*/
...
...
@@ -59,6 +62,12 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
min_cache
=
use_async_io
?
IO_SIZE
*
4
:
IO_SIZE
*
2
;
if
(
type
==
READ_CACHE
)
{
/* Assume file isn't growing */
if
(
cache_myflags
&
MY_DONT_CHECK_FILESIZE
)
{
cache_myflags
&=
~
MY_DONT_CHECK_FILESIZE
;
}
else
{
my_off_t
file_pos
,
end_of_file
;
if
((
file_pos
=
my_tell
(
file
,
MYF
(
0
))
==
MY_FILEPOS_ERROR
))
DBUG_RETURN
(
1
);
...
...
@@ -72,6 +81,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
use_async_io
=
0
;
/* No nead to use async */
}
}
}
for
(;;)
{
...
...
@@ -545,7 +555,6 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
return
error
;
}
/* Flush write cache */
int
flush_io_cache
(
IO_CACHE
*
info
)
...
...
@@ -565,7 +574,9 @@ int flush_io_cache(IO_CACHE *info)
length
=
(
uint
)
(
info
->
rc_pos
-
info
->
buffer
);
if
(
info
->
seek_not_done
)
{
/* File touched, do seek */
VOID
(
my_seek
(
info
->
file
,
info
->
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
)));
if
(
my_seek
(
info
->
file
,
info
->
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
))
==
MY_FILEPOS_ERROR
)
DBUG_RETURN
((
info
->
error
=
-
1
));
info
->
seek_not_done
=
0
;
}
info
->
rc_pos
=
info
->
buffer
;
...
...
mysys/my_vsnprintf.c
View file @
e69becf1
...
...
@@ -21,74 +21,49 @@
#include <stdarg.h>
#include <m_ctype.h>
int
my_vsnprintf
(
char
*
str
,
size_t
n
,
const
char
*
fmt
,
va_list
ap
)
int
my_vsnprintf
(
char
*
to
,
size_t
n
,
const
char
*
fmt
,
va_list
ap
)
{
uint
olen
=
0
,
plen
;
const
char
*
tpos
;
reg1
char
*
endpos
;
reg2
char
*
par
;
char
*
ebuff
=
str
;
char
*
start
=
to
,
*
end
=
to
+
n
-
1
;
endpos
=
ebuff
;
tpos
=
fmt
;
while
(
*
tpos
)
for
(;
*
fmt
;
fmt
++
)
{
if
(
tpos
[
0
]
!=
'%'
)
if
(
fmt
[
0
]
!=
'%'
)
{
if
(
olen
+
1
>=
n
)
if
(
to
==
end
)
/* End of buffer */
break
;
*
endpos
++=
*
tpos
++
;
/* Copy ordinary char */
olen
++
;
*
to
++=
*
fmt
;
/* Copy ordinary char */
continue
;
}
if
(
*++
tpos
==
'%'
)
/* test if %% */
{
olen
--
;
}
else
{
/* Skipp if max size is used (to be compatible with printf) */
while
(
isdigit
(
*
tpos
)
||
*
tpos
==
'.'
||
*
tpos
==
'-'
)
tpos
++
;
if
(
*
tpos
==
's'
)
/* String parameter */
while
(
isdigit
(
*
fmt
)
||
*
fmt
==
'.'
||
*
fmt
==
'-'
)
fmt
++
;
if
(
*
fmt
==
's'
)
/* String parameter */
{
par
=
va_arg
(
ap
,
char
*
);
plen
=
(
uint
)
strlen
(
par
);
if
(
olen
+
plen
<
n
)
/* Replace if possible */
reg2
char
*
par
=
va_arg
(
ap
,
char
*
);
uint
plen
=
(
uint
)
strlen
(
par
);
if
((
uint
)
(
end
-
to
)
>
plen
)
/* Replace if possible */
{
endpos
=
strmov
(
endpos
,
par
);
tpos
++
;
olen
+=
plen
;
to
=
strmov
(
to
,
par
);
continue
;
}
}
else
if
(
*
tpos
==
'd'
||
*
tpos
==
'u'
)
/* Integer parameter */
else
if
(
*
fmt
==
'd'
||
*
fmt
==
'u'
)
/* Integer parameter */
{
register
int
iarg
;
if
((
uint
)
(
end
-
to
)
<
16
)
break
;
iarg
=
va_arg
(
ap
,
int
);
if
(
olen
+
16
>=
n
)
break
;
if
(
*
tpos
==
'd'
)
plen
=
(
uint
)
(
int2str
((
long
)
iarg
,
endpos
,
-
10
)
-
endpos
);
if
(
*
fmt
==
'd'
)
to
=
int10_to_str
((
long
)
iarg
,
to
,
-
10
);
else
plen
=
(
uint
)
(
int2str
((
long
)
(
uint
)
iarg
,
endpos
,
10
)
-
endpos
);
if
(
olen
+
plen
<
n
)
/* Replace parameter if possible */
{
endpos
+=
plen
;
tpos
++
;
olen
+=
plen
;
to
=
int10_to_str
((
long
)
(
uint
)
iarg
,
to
,
10
);
continue
;
}
/* We come here on '%%', unknown code or too long parameter */
if
(
to
==
end
)
break
;
*
to
++=
'%'
;
/* % used as % or unknown code */
}
}
*
endpos
++=
'%'
;
/* % used as % or unknown code */
}
*
endpos
=
'\0'
;
/* End of errmessage */
return
olen
;
*
to
=
'\0'
;
/* End of errmessage */
return
(
uint
)
(
to
-
start
);
}
sql/log.cc
View file @
e69becf1
This diff is collapsed.
Click to expand it.
sql/log_event.cc
View file @
e69becf1
This diff is collapsed.
Click to expand it.
sql/log_event.h
View file @
e69becf1
...
...
@@ -65,9 +65,9 @@ public:
int
valid_exec_time
;
// if false, the exec time setting is bogus
uint32
server_id
;
int
write
(
FIL
E
*
file
);
int
write_header
(
FIL
E
*
file
);
virtual
int
write_data
(
FIL
E
*
file
__attribute__
((
unused
)))
{
return
0
;
}
int
write
(
IO_CACH
E
*
file
);
int
write_header
(
IO_CACH
E
*
file
);
virtual
int
write_data
(
IO_CACH
E
*
file
__attribute__
((
unused
)))
{
return
0
;
}
virtual
Log_event_type
get_type_code
()
=
0
;
Log_event
(
time_t
when_arg
,
ulong
exec_time_arg
=
0
,
int
valid_exec_time_arg
=
0
,
uint32
server_id
=
0
)
:
when
(
when_arg
),
...
...
@@ -92,11 +92,11 @@ public:
void
print_header
(
FILE
*
file
);
// if mutex is 0, the read will proceed without mutex
static
Log_event
*
read_log_event
(
FIL
E
*
file
,
pthread_mutex_t
*
log_lock
);
static
Log_event
*
read_log_event
(
IO_CACH
E
*
file
,
pthread_mutex_t
*
log_lock
);
static
Log_event
*
read_log_event
(
const
char
*
buf
,
int
max_buf
);
#ifndef MYSQL_CLIENT
static
int
read_log_event
(
FIL
E
*
file
,
String
*
packet
,
static
int
read_log_event
(
IO_CACH
E
*
file
,
String
*
packet
,
pthread_mutex_t
*
log_lock
);
#endif
...
...
@@ -132,18 +132,18 @@ public:
}
#endif
Query_log_event
(
FIL
E
*
file
,
time_t
when
,
uint32
server_id
);
Query_log_event
(
IO_CACH
E
*
file
,
time_t
when
,
uint32
server_id
);
Query_log_event
(
const
char
*
buf
,
int
max_buf
);
~
Query_log_event
()
{
if
(
data_buf
)
{
my_free
((
gptr
)
data_buf
,
MYF
(
0
));
my_free
((
gptr
)
data_buf
,
MYF
(
0
));
}
}
Log_event_type
get_type_code
()
{
return
QUERY_EVENT
;
}
int
write
(
FIL
E
*
file
);
int
write_data
(
FIL
E
*
file
);
// returns 0 on success, -1 on error
int
write
(
IO_CACH
E
*
file
);
int
write_data
(
IO_CACH
E
*
file
);
// returns 0 on success, -1 on error
int
get_data_size
()
{
return
q_len
+
db_len
+
2
+
...
...
@@ -183,6 +183,8 @@ class Load_log_event: public Log_event
{
protected:
char
*
data_buf
;
void
Load_log_event
::
copy_log_event
(
const
char
*
buf
,
ulong
data_len
);
public:
int
thread_id
;
uint32
table_name_len
;
...
...
@@ -272,17 +274,17 @@ public:
void
set_fields
(
List
<
Item
>
&
fields
);
#endif
Load_log_event
(
FILE
*
file
,
time_t
when
,
uint32
server_id
);
Load_log_event
(
IO_CACHE
*
file
,
time_t
when
,
uint32
server_id
);
Load_log_event
(
const
char
*
buf
,
int
max_buf
);
~
Load_log_event
()
{
if
(
data_buf
)
{
my_free
((
gptr
)
data_buf
,
MYF
(
0
));
my_free
((
gptr
)
data_buf
,
MYF
(
0
));
}
}
Log_event_type
get_type_code
()
{
return
LOAD_EVENT
;
}
int
write_data
(
FIL
E
*
file
);
// returns 0 on success, -1 on error
int
write_data
(
IO_CACH
E
*
file
);
// returns 0 on success, -1 on error
int
get_data_size
()
{
return
table_name_len
+
2
+
db_len
+
2
+
fname_len
...
...
@@ -311,30 +313,26 @@ public:
created
=
(
uint32
)
when
;
memcpy
(
server_version
,
::
server_version
,
sizeof
(
server_version
));
}
Start_log_event
(
FIL
E
*
file
,
time_t
when_arg
,
uint32
server_id
)
:
Start_log_event
(
IO_CACH
E
*
file
,
time_t
when_arg
,
uint32
server_id
)
:
Log_event
(
when_arg
,
0
,
0
,
server_id
)
{
char
buf
[
sizeof
(
server_version
)
+
sizeof
(
binlog_version
)
+
sizeof
(
created
)];
my_fseek
(
file
,
4L
,
MY_SEEK_CUR
,
MYF
(
MY_WME
));
// skip the event length
if
(
my_fread
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
),
MYF
(
MY_NABP
|
MY_WME
)))
sizeof
(
created
)
+
4
];
if
(
my_b_read
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
)))
return
;
binlog_version
=
uint2korr
(
buf
);
memcpy
(
server_version
,
buf
+
2
,
sizeof
(
server_version
));
created
=
uint4korr
(
buf
+
2
+
sizeof
(
server_version
));
binlog_version
=
uint2korr
(
buf
+
4
);
memcpy
(
server_version
,
buf
+
6
,
sizeof
(
server_version
));
created
=
uint4korr
(
buf
+
6
+
sizeof
(
server_version
));
}
Start_log_event
(
const
char
*
buf
);
~
Start_log_event
()
{}
Log_event_type
get_type_code
()
{
return
START_EVENT
;}
int
write_data
(
FIL
E
*
file
)
int
write_data
(
IO_CACH
E
*
file
)
{
if
(
my_fwrite
(
file
,
(
byte
*
)
&
binlog_version
,
sizeof
(
binlog_version
),
MYF
(
MY_NABP
|
MY_WME
))
||
my_fwrite
(
file
,
(
byte
*
)
server_version
,
sizeof
(
server_version
),
MYF
(
MY_NABP
|
MY_WME
))
||
my_fwrite
(
file
,
(
byte
*
)
&
created
,
sizeof
(
created
),
MYF
(
MY_NABP
|
MY_WME
)))
if
(
my_b_write
(
file
,
(
byte
*
)
&
binlog_version
,
sizeof
(
binlog_version
))
||
my_b_write
(
file
,
(
byte
*
)
server_version
,
sizeof
(
server_version
))
||
my_b_write
(
file
,
(
byte
*
)
&
created
,
sizeof
(
created
)))
return
-
1
;
return
0
;
}
...
...
@@ -354,12 +352,12 @@ public:
Intvar_log_event
(
uchar
type_arg
,
ulonglong
val_arg
)
:
Log_event
(
time
(
NULL
)),
val
(
val_arg
),
type
(
type_arg
)
{}
Intvar_log_event
(
FIL
E
*
file
,
time_t
when
,
uint32
server_id
);
Intvar_log_event
(
IO_CACH
E
*
file
,
time_t
when
,
uint32
server_id
);
Intvar_log_event
(
const
char
*
buf
);
~
Intvar_log_event
()
{}
Log_event_type
get_type_code
()
{
return
INTVAR_EVENT
;}
int
get_data_size
()
{
return
sizeof
(
type
)
+
sizeof
(
val
);}
int
write_data
(
FIL
E
*
file
);
int
write_data
(
IO_CACH
E
*
file
);
void
print
(
FILE
*
file
,
bool
short_form
=
0
);
...
...
@@ -370,10 +368,11 @@ class Stop_log_event: public Log_event
public:
Stop_log_event
()
:
Log_event
(
time
(
NULL
))
{}
Stop_log_event
(
FIL
E
*
file
,
time_t
when_arg
,
uint32
server_id
)
:
Stop_log_event
(
IO_CACH
E
*
file
,
time_t
when_arg
,
uint32
server_id
)
:
Log_event
(
when_arg
,
0
,
0
,
server_id
)
{
my_fseek
(
file
,
4L
,
MY_SEEK_CUR
,
MYF
(
MY_WME
));
// skip the event length
char
skip
[
4
];
my_b_read
(
file
,
skip
,
sizeof
(
skip
));
// skip the event length
}
Stop_log_event
(
const
char
*
buf
)
:
Log_event
(
buf
)
{
...
...
@@ -397,7 +396,7 @@ public:
alloced
(
0
)
{}
Rotate_log_event
(
FIL
E
*
file
,
time_t
when
,
uint32
server_id
)
;
Rotate_log_event
(
IO_CACH
E
*
file
,
time_t
when
,
uint32
server_id
)
;
Rotate_log_event
(
const
char
*
buf
,
int
max_buf
);
~
Rotate_log_event
()
{
...
...
@@ -406,7 +405,7 @@ public:
}
Log_event_type
get_type_code
()
{
return
ROTATE_EVENT
;}
int
get_data_size
()
{
return
ident_len
;}
int
write_data
(
FIL
E
*
file
);
int
write_data
(
IO_CACH
E
*
file
);
void
print
(
FILE
*
file
,
bool
short_form
=
0
);
};
...
...
sql/mf_iocache.cc
View file @
e69becf1
...
...
@@ -32,17 +32,19 @@
#define MAP_TO_USE_RAID
#include "mysql_priv.h"
#include <mysys_err.h>
#ifdef HAVE_AIOWAIT
#include <mysys_err.h>
#include <errno.h>
static
void
my_aiowait
(
my_aio_result
*
result
);
#endif
/* if cachesize == 0 then use default cachesize (from s-file) */
/* returns 0 if we have enough memory */
extern
"C"
{
/*
** if cachesize == 0 then use default cachesize (from s-file)
** if file == -1 then real_open_cached_file() will be called.
** returns 0 if ok
*/
int
init_io_cache
(
IO_CACHE
*
info
,
File
file
,
uint
cachesize
,
enum
cache_type
type
,
my_off_t
seek_offset
,
...
...
@@ -60,6 +62,12 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
min_cache
=
use_async_io
?
IO_SIZE
*
4
:
IO_SIZE
*
2
;
if
(
type
==
READ_CACHE
)
{
/* Assume file isn't growing */
if
(
cache_myflags
&
MY_DONT_CHECK_FILESIZE
)
{
cache_myflags
&=
~
MY_DONT_CHECK_FILESIZE
;
}
else
{
my_off_t
file_pos
,
end_of_file
;
if
((
file_pos
=
my_tell
(
file
,
MYF
(
0
))
==
MY_FILEPOS_ERROR
))
DBUG_RETURN
(
1
);
...
...
@@ -73,7 +81,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
use_async_io
=
0
;
/* No nead to use async */
}
}
}
if
((
int
)
type
<
(
int
)
READ_NET
)
{
for
(;;)
...
...
@@ -167,7 +175,8 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
DBUG_ENTER
(
"reinit_io_cache"
);
info
->
seek_not_done
=
test
(
info
->
file
>=
0
);
/* Seek not done */
if
(
!
clear_cache
&&
seek_offset
>=
info
->
pos_in_file
&&
if
(
!
clear_cache
&&
seek_offset
>=
info
->
pos_in_file
&&
seek_offset
<=
info
->
pos_in_file
+
(
uint
)
(
info
->
rc_end
-
info
->
rc_request_pos
))
{
/* use current buffer */
...
...
@@ -231,6 +240,7 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
{
uint
length
,
diff_length
,
left_length
;
my_off_t
max_length
,
pos_in_file
;
memcpy
(
Buffer
,
info
->
rc_pos
,
(
size_t
)
(
left_length
=
(
uint
)
(
info
->
rc_end
-
info
->
rc_pos
)));
Buffer
+=
left_length
;
...
...
@@ -607,7 +617,9 @@ int flush_io_cache(IO_CACHE *info)
length
=
(
uint
)
(
info
->
rc_pos
-
info
->
buffer
);
if
(
info
->
seek_not_done
)
{
/* File touched, do seek */
VOID
(
my_seek
(
info
->
file
,
info
->
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
)));
if
(
my_seek
(
info
->
file
,
info
->
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
))
==
MY_FILEPOS_ERROR
)
DBUG_RETURN
((
info
->
error
=
-
1
));
info
->
seek_not_done
=
0
;
}
info
->
rc_pos
=
info
->
buffer
;
...
...
@@ -644,4 +656,4 @@ int end_io_cache(IO_CACHE *info)
DBUG_RETURN
(
error
);
}
/* end_io_cache */
}
}
/* extern "C" */
sql/mysqlbinlog.cc
View file @
e69becf1
...
...
@@ -55,7 +55,7 @@ static struct option long_options[] =
{
"password"
,
required_argument
,
0
,
'p'
},
{
"position"
,
required_argument
,
0
,
'j'
},
#ifndef DBUG_OFF
{
"debug"
,
required
_argument
,
0
,
'#'
}
{
"debug"
,
optional
_argument
,
0
,
'#'
}
#endif
};
...
...
@@ -151,7 +151,7 @@ static int parse_args(int *argc, char*** argv)
{
int
c
,
opt_index
=
0
;
while
((
c
=
getopt_long
(
*
argc
,
*
argv
,
"so:#:h:j:u:p:P:t:?"
,
long_options
,
while
((
c
=
getopt_long
(
*
argc
,
*
argv
,
"so:#:
:
h:j:u:p:P:t:?"
,
long_options
,
&
opt_index
))
!=
EOF
)
{
switch
(
c
)
...
...
@@ -310,24 +310,43 @@ Unfortunately, no sweepstakes today, adjusted position to 4\n");
static
void
dump_local_log_entries
(
const
char
*
logname
)
{
FILE
*
file
;
File
fd
;
IO_CACHE
cache
,
*
file
=
&
cache
;
int
rec_count
=
0
;
if
(
logname
&&
logname
[
0
]
!=
'-'
)
file
=
my_fopen
(
logname
,
O_RDONLY
|
O_BINARY
,
MYF
(
MY_WME
));
if
(
logname
&&
logname
[
0
]
!=
'-'
)
{
if
((
fd
=
my_open
(
logname
,
O_RDONLY
|
O_BINARY
,
MYF
(
MY_WME
)))
<
0
)
exit
(
1
);
if
(
init_io_cache
(
file
,
fd
,
0
,
READ_CACHE
,
(
my_off_t
)
position
,
0
,
MYF
(
MY_WME
|
MY_NABP
)))
exit
(
1
);
}
else
file
=
stdin
;
if
(
!
file
)
die
(
"Could not open log file %s"
,
logname
);
if
(
my_fseek
(
file
,
position
,
MY_SEEK_SET
,
MYF
(
MY_WME
)))
die
(
"failed on my_fseek()"
);
{
if
(
init_io_cache
(
file
,
fileno
(
stdout
),
0
,
READ_CACHE
,
(
my_off_t
)
0
,
0
,
MYF
(
MY_WME
|
MY_NABP
|
MY_DONT_CHECK_FILESIZE
)))
exit
(
1
);
if
(
position
)
{
/* skip 'position' characters from stdout */
char
buff
[
IO_SIZE
];
my_off_t
length
,
tmp
;
for
(
length
=
position
;
length
>
0
;
length
-=
tmp
)
{
tmp
=
min
(
length
,
sizeof
(
buff
));
if
(
my_b_read
(
file
,
buff
,
tmp
))
exit
(
1
);
}
}
file
->
pos_in_file
=
position
;
file
->
seek_not_done
=
0
;
}
if
(
!
position
)
if
(
!
position
)
{
char
magic
[
4
];
if
(
my_fread
(
file
,
(
byte
*
)
magic
,
sizeof
(
magic
),
MYF
(
MY_NABP
|
MY_WME
)))
if
(
my_b_read
(
file
,
(
byte
*
)
magic
,
sizeof
(
magic
)))
die
(
"I/O error reading binlog magic number"
);
if
(
memcmp
(
magic
,
BINLOG_MAGIC
,
4
))
die
(
"Bad magic number"
);
...
...
@@ -336,23 +355,24 @@ static void dump_local_log_entries(const char* logname)
while
(
1
)
{
Log_event
*
ev
=
Log_event
::
read_log_event
(
file
,
0
);
if
(
!
ev
)
if
(
!
feof
(
file
))
if
(
!
ev
)
{
if
(
file
->
error
)
die
(
"Could not read entry at offset %ld : Error in log format or \
read error"
,
my_ftell
(
file
,
MYF
(
MY_WME
)));
else
my_b_tell
(
file
));
break
;
if
(
rec_count
>=
offset
)
}
if
(
rec_count
>=
offset
)
ev
->
print
(
stdout
,
short_form
);
rec_count
++
;
delete
ev
;
}
my_fclose
(
file
,
MYF
(
MY_WME
)
);
my_close
(
fd
,
MYF
(
MY_WME
));
end_io_cache
(
file
);
}
int
main
(
int
argc
,
char
**
argv
)
{
MY_INIT
(
argv
[
0
]);
...
...
@@ -370,7 +390,7 @@ int main(int argc, char** argv)
mysql
=
safe_connect
();
}
if
(
table
)
if
(
table
)
{
if
(
!
use_remote
)
die
(
"You must specify connection parameter to get table dump"
);
...
...
@@ -382,14 +402,14 @@ int main(int argc, char** argv)
dump_remote_table
(
&
mysql
->
net
,
db
,
tbl
);
}
else
{
while
(
--
argc
>=
0
)
{
dump_log_entries
(
*
(
argv
++
));
}
if
(
use_remote
)
}
if
(
use_remote
)
mc_mysql_close
(
mysql
);
return
0
;
}
...
...
sql/net_pkg.cc
View file @
e69becf1
sql/sql_class.cc
View file @
e69becf1
...
...
@@ -113,11 +113,17 @@ THD::THD()
ull
=
0
;
system_thread
=
0
;
bzero
((
char
*
)
&
mem_root
,
sizeof
(
mem_root
));
#if defined(HAVE_BDB) || defined(HAVE_INNOBASE) || defined(HAVE_GEMENI)
if
(
open_cached_file
(
&
transactions
.
trans_log
,
mysql_tempdir
,
LOG_PREFIX
,
0
,
MYF
(
MY_WME
)))
killed
=
1
;
transaction
.
bdb_lock_count
=
0
;
#endif
transaction
.
bdb_tid
=
0
;
#ifdef __WIN__
real_id
=
0
;
#endif
transaction
.
bdb_lock_count
=
0
;
transaction
.
bdb_tid
=
0
;
}
THD
::~
THD
()
...
...
@@ -136,6 +142,9 @@ THD::~THD()
close_thread_tables
(
this
);
}
close_temporary_tables
(
this
);
#if defined(HAVE_BDB) || defined(HAVE_INNOBASE) || defined(HAVE_GEMENI)
close_cached_file
(
transactions
.
trans_log
);
#endif
if
(
global_read_lock
)
{
pthread_mutex_lock
(
&
LOCK_open
);
...
...
sql/sql_class.h
View file @
e69becf1
...
...
@@ -82,16 +82,16 @@ typedef struct st_master_info
}
MASTER_INFO
;
class
MYSQL_LOG
{
public:
private:
pthread_mutex_t
LOCK_log
,
LOCK_index
;
File
file
,
index_file
;
time_t
last_time
,
query_start
;
IO_CACHE
log_file
;
File
index_file
;
char
*
name
;
enum_log_type
log_type
;
volatile
enum_log_type
log_type
;
char
time_buff
[
20
],
db
[
NAME_LEN
+
1
];
char
log_file_name
[
FN_REFLEN
],
index_file_name
[
FN_REFLEN
];
bool
write_error
,
inited
;
bool
write_error
,
inited
,
opened
;
bool
no_rotate
;
// for binlog - if log name can never change
// we should not try to rotate it or write any rotation events
// the user should use FLUSH MASTER instead of FLUSH LOGS for
...
...
@@ -114,7 +114,7 @@ public:
int
generate_new_name
(
char
*
new_name
,
const
char
*
old_name
);
void
make_log_name
(
char
*
buf
,
const
char
*
log_ident
);
bool
is_active
(
const
char
*
log_file_name
);
void
flush
(
void
);
//
void flush(void);
void
close
(
bool
exiting
=
0
);
// if we are exiting, we also want to close the
// index file
...
...
@@ -270,6 +270,7 @@ public:
thr_lock_type
update_lock_default
;
delayed_insert
*
di
;
struct
st_transactions
{
IO_CACHE
trans_log
;
void
*
bdb_tid
;
uint
bdb_lock_count
;
}
transaction
;
...
...
sql/sql_parse.cc
View file @
e69becf1
...
...
@@ -2439,7 +2439,7 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
bool
result
=
0
;
select_errors
=
0
;
/* Write if more errors */
mysql_log
.
flush
();
// Flush log
//
mysql_log.flush(); // Flush log
if
(
options
&
REFRESH_GRANT
)
{
acl_reload
();
...
...
sql/sql_repl.cc
View file @
e69becf1
...
...
@@ -93,54 +93,74 @@ static int send_file(THD *thd)
DBUG_RETURN
(
error
);
}
static
File
open_log
(
IO_CACHE
*
log
,
const
char
*
log_file_name
,
const
char
**
errmsg
)
{
File
file
;
char
magic
[
4
];
if
((
file
=
my_open
(
log_file_name
,
O_RDONLY
|
O_BINARY
,
MYF
(
MY_WME
)))
<
0
||
init_io_cache
(
log
,
file
,
IO_SIZE
*
2
,
READ_CACHE
,
0
,
0
,
MYF
(
MY_WME
)))
{
*
errmsg
=
"Could not open log file"
;
// This will not be sent
goto
err
;
}
if
(
my_b_read
(
log
,
(
byte
*
)
magic
,
sizeof
(
magic
)))
{
*
errmsg
=
"I/O error reading binlog magic number"
;
goto
err
;
}
if
(
memcmp
(
magic
,
BINLOG_MAGIC
,
4
))
{
*
errmsg
=
"Binlog has bad magic number, fire your magician"
;
goto
err
;
}
return
file
;
err:
if
(
file
>
0
)
my_close
(
file
,
MYF
(
0
));
end_io_cache
(
log
);
return
-
1
;
}
void
mysql_binlog_send
(
THD
*
thd
,
char
*
log_ident
,
ulong
pos
,
ushort
flags
)
{
LOG_INFO
linfo
;
char
*
log_file_name
=
linfo
.
log_file_name
;
char
search_file_name
[
FN_REFLEN
];
char
magic
[
4
]
;
F
ILE
*
log
=
NULL
;
IO_CACHE
log
;
F
ile
file
=
-
1
;
String
*
packet
=
&
thd
->
packet
;
int
error
;
const
char
*
errmsg
=
"Unknown error"
;
NET
*
net
=
&
thd
->
net
;
DBUG_ENTER
(
"mysql_binlog_send"
);
bzero
((
char
*
)
&
log
,
sizeof
(
log
));
if
(
!
mysql_bin_log
.
is_open
())
{
errmsg
=
"Binary log is not open"
;
goto
err
;
}
if
(
log_ident
[
0
])
if
(
log_ident
[
0
])
mysql_bin_log
.
make_log_name
(
search_file_name
,
log_ident
);
else
search_file_name
[
0
]
=
0
;
if
(
mysql_bin_log
.
find_first_log
(
&
linfo
,
search_file_name
))
if
(
mysql_bin_log
.
find_first_log
(
&
linfo
,
search_file_name
))
{
errmsg
=
"Could not find first log"
;
goto
err
;
}
log
=
my_fopen
(
log_file_name
,
O_RDONLY
|
O_BINARY
,
MYF
(
MY_WME
));
if
(
!
log
)
{
errmsg
=
"Could not open log file"
;
goto
err
;
}
if
(
my_fread
(
log
,
(
byte
*
)
magic
,
sizeof
(
magic
),
MYF
(
MY_NABP
|
MY_WME
)))
{
errmsg
=
"I/O error reading binlog magic number"
;
goto
err
;
}
if
(
memcmp
(
magic
,
BINLOG_MAGIC
,
4
))
{
errmsg
=
"Binlog has bad magic number, fire your magician"
;
if
((
file
=
open_log
(
&
log
,
log_file_name
,
&
errmsg
))
<
0
)
goto
err
;
}
if
(
pos
<
4
)
{
...
...
@@ -149,13 +169,7 @@ sweepstakes if you report the bug";
goto
err
;
}
if
(
my_fseek
(
log
,
pos
,
MY_SEEK_SET
,
MYF
(
MY_WME
))
==
MY_FILEPOS_ERROR
)
{
errmsg
=
"Error on fseek()"
;
goto
err
;
}
my_b_seek
(
&
log
,
pos
);
// Seek will done on next read
packet
->
length
(
0
);
packet
->
append
(
"
\0
"
,
1
);
// we need to start a packet with something other than 255
...
...
@@ -165,7 +179,7 @@ sweepstakes if you report the bug";
{
pthread_mutex_t
*
log_lock
=
mysql_bin_log
.
get_log_lock
();
while
(
!
(
error
=
Log_event
::
read_log_event
(
log
,
packet
,
log_lock
)))
while
(
!
(
error
=
Log_event
::
read_log_event
(
&
log
,
packet
,
log_lock
)))
{
if
(
my_net_write
(
net
,
(
char
*
)
packet
->
ptr
(),
packet
->
length
())
)
{
...
...
@@ -221,7 +235,7 @@ sweepstakes if you report the bug";
// if we did not miss anything, we just wait for other threads
// to signal us
{
clearerr
(
log
)
;
log
.
error
=
0
;
// tell the kill thread how to wake us up
pthread_mutex_lock
(
&
thd
->
mysys_var
->
mutex
);
...
...
@@ -235,7 +249,7 @@ sweepstakes if you report the bug";
// no one will update the log while we are reading
// now, but we'll be quick and just read one record
switch
(
Log_event
::
read_log_event
(
log
,
packet
,
log_lock
))
switch
(
Log_event
::
read_log_event
(
&
log
,
packet
,
log_lock
))
{
case
0
:
read_packet
=
1
;
...
...
@@ -288,8 +302,7 @@ sweepstakes if you report the bug";
errmsg
=
"error reading log entry"
;
goto
err
;
}
clearerr
(
log
);
log
.
error
=
0
;
}
}
else
...
...
@@ -312,25 +325,10 @@ sweepstakes if you report the bug";
if
(
loop_breaker
)
break
;
(
void
)
my_fclose
(
log
,
MYF
(
MY_WME
));
log
=
my_fopen
(
log_file_name
,
O_RDONLY
|
O_BINARY
,
MYF
(
MY_WME
));
if
(
!
log
)
{
errmsg
=
"Could not open next log"
;
end_io_cache
(
&
log
);
(
void
)
my_close
(
file
,
MYF
(
MY_WME
));
if
((
file
=
open_log
(
&
log
,
log_file_name
,
&
errmsg
))
<
0
)
goto
err
;
}
//check the magic
if
(
my_fread
(
log
,
(
byte
*
)
magic
,
sizeof
(
magic
),
MYF
(
MY_NABP
|
MY_WME
)))
{
errmsg
=
"I/O error reading binlog magic number"
;
goto
err
;
}
if
(
memcmp
(
magic
,
BINLOG_MAGIC
,
4
))
{
errmsg
=
"Binlog has bad magic number, fire your magician"
;
goto
err
;
}
// fake Rotate_log event just in case it did not make it to the log
// otherwise the slave make get confused about the offset
...
...
@@ -362,15 +360,17 @@ sweepstakes if you report the bug";
}
}
(
void
)
my_fclose
(
log
,
MYF
(
MY_WME
));
end_io_cache
(
&
log
);
(
void
)
my_close
(
file
,
MYF
(
MY_WME
));
send_eof
(
&
thd
->
net
);
thd
->
proc_info
=
"waiting to finalize termination"
;
DBUG_VOID_RETURN
;
err:
thd
->
proc_info
=
"waiting to finalize termination"
;
if
(
log
)
(
void
)
my_fclose
(
log
,
MYF
(
MY_WME
));
end_io_cache
(
&
log
);
if
(
file
>=
0
)
(
void
)
my_close
(
file
,
MYF
(
MY_WME
));
send_error
(
&
thd
->
net
,
0
,
errmsg
);
DBUG_VOID_RETURN
;
}
...
...
sql/sql_string.cc
View file @
e69becf1
...
...
@@ -95,17 +95,6 @@ bool String::realloc(uint32 alloc_length)
return
FALSE
;
}
#ifdef NOT_NEEDED
bool
String
::
set
(
long
num
)
{
if
(
alloc
(
14
))
return
TRUE
;
str_length
=
(
uint32
)
(
int10_to_str
(
num
,
Ptr
,
-
10
)
-
Ptr
);
return
FALSE
;
}
#endif
bool
String
::
set
(
longlong
num
)
{
if
(
alloc
(
21
))
...
...
@@ -274,6 +263,7 @@ bool String::append(const char *s,uint32 arg_length)
return
FALSE
;
}
#ifdef TO_BE_REMOVED
bool
String
::
append
(
FILE
*
file
,
uint32
arg_length
,
myf
my_flags
)
{
if
(
realloc
(
str_length
+
arg_length
))
...
...
@@ -286,6 +276,20 @@ bool String::append(FILE* file, uint32 arg_length, myf my_flags)
str_length
+=
arg_length
;
return
FALSE
;
}
#endif
bool
String
::
append
(
IO_CACHE
*
file
,
uint32
arg_length
)
{
if
(
realloc
(
str_length
+
arg_length
))
return
TRUE
;
if
(
my_b_read
(
file
,
(
byte
*
)
Ptr
+
str_length
,
arg_length
))
{
shrink
(
str_length
);
return
TRUE
;
}
str_length
+=
arg_length
;
return
FALSE
;
}
uint32
String
::
numchars
()
{
...
...
sql/sql_string.h
View file @
e69becf1
...
...
@@ -152,7 +152,7 @@ public:
bool
copy
(
const
char
*
s
,
uint32
arg_length
);
// Allocate new string
bool
append
(
const
String
&
s
);
bool
append
(
const
char
*
s
,
uint32
arg_length
=
0
);
bool
append
(
FILE
*
file
,
uint32
arg_length
,
myf
my_flags
);
bool
append
(
IO_CACHE
*
file
,
uint32
arg_length
);
int
strstr
(
const
String
&
search
,
uint32
offset
=
0
);
// Returns offset to substring or -1
int
strrstr
(
const
String
&
search
,
uint32
offset
=
0
);
// Returns offset to substring or -1
bool
replace
(
uint32
offset
,
uint32
arg_length
,
const
String
&
to
);
...
...
sql/time.cc
View file @
e69becf1
...
...
@@ -413,16 +413,6 @@ ulong convert_month_to_period(ulong month)
return
year
*
100
+
month
%
12
+
1
;
}
#ifdef NOT_NEEDED
ulong
add_to_period
(
ulong
period
,
int
months
)
{
if
(
period
==
0L
)
return
0L
;
return
convert_month_to_period
(
convert_period_to_month
(
period
)
+
months
);
}
#endif
/*****************************************************************************
** convert a timestamp string to a TIME value.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment