Bug#30907

  "Regression: "--innodb_autoinc_lock_mode=0" (off) not same as older releases"
Bug#28430
  "Failure in replication of innodb partitioned tables on row/mixed format"
Bug#30888
  "Innodb table + stored procedure + row deletion = server crash"

  Apply Oracle patch from Sunny
  Include tests cases by Omer
  Ensure that innobase_read_and_init_auto performs table autoinc lock when lock_mode = 0
  No need for "if" guard around row_unlock_table_autoinc_for_mysql() because
  it already performs same check.
  Make autoinc_lock_mode variable read-only for duration of running mysqld process.
parent cf2b6a97
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
use test;
CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE='innodb';
CREATE TABLE test.bykey_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE='innodb'
PARTITION BY KEY(id) partitions 5;
CREATE TABLE test.byrange_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE='innodb'
PARTITION BY RANGE(id)
SUBPARTITION BY hash(id) subpartitions 2
(PARTITION pa1 values less than (10),
PARTITION pa2 values less than (20),
PARTITION pa3 values less than (30),
PARTITION pa4 values less than (40),
PARTITION pa5 values less than (50),
PARTITION pa6 values less than (60),
PARTITION pa7 values less than (70),
PARTITION pa8 values less than (80),
PARTITION pa9 values less than (90),
PARTITION pa10 values less than (100),
PARTITION pa11 values less than MAXVALUE);
CREATE PROCEDURE test.proc_norm()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.regular_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.regular_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CREATE PROCEDURE test.proc_bykey()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.bykey_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.bykey_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.bykey_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CREATE PROCEDURE test.proc_byrange()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user = CURRENT_USER();
SET local_uuid=UUID();
WHILE ins_count > 0 DO
INSERT INTO test.byrange_tbl VALUES (NULL, NOW(), USER(), UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.byrange_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.byrange_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CALL test.proc_norm();
SELECT count(*) as "Master regular" FROM test.regular_tbl;
Master regular 500
CALL test.proc_bykey();
SELECT count(*) as "Master bykey" FROM test.bykey_tbl;
Master bykey 811
CALL test.proc_byrange();
SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
Master byrange 996
show create table test.byrange_tbl;
Table byrange_tbl
Create Table CREATE TABLE `byrange_tbl` (
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`user` char(255) DEFAULT NULL,
`uuidf` longblob,
`fkid` mediumint(9) DEFAULT NULL,
`filler` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) SUBPARTITION BY HASH (id) SUBPARTITIONS 2 (PARTITION pa1 VALUES LESS THAN (10) ENGINE = MyISAM, PARTITION pa2 VALUES LESS THAN (20) ENGINE = MyISAM, PARTITION pa3 VALUES LESS THAN (30) ENGINE = MyISAM, PARTITION pa4 VALUES LESS THAN (40) ENGINE = MyISAM, PARTITION pa5 VALUES LESS THAN (50) ENGINE = MyISAM, PARTITION pa6 VALUES LESS THAN (60) ENGINE = MyISAM, PARTITION pa7 VALUES LESS THAN (70) ENGINE = MyISAM, PARTITION pa8 VALUES LESS THAN (80) ENGINE = MyISAM, PARTITION pa9 VALUES LESS THAN (90) ENGINE = MyISAM, PARTITION pa10 VALUES LESS THAN (100) ENGINE = MyISAM, PARTITION pa11 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */
show slave status;
Slave_IO_State Waiting for master to send event
Master_Host 127.0.0.1
Master_User root
Master_Port 12000
Connect_Retry 1
Master_Log_File master-bin.000001
Read_Master_Log_Pos 776796
Relay_Log_File slave-relay-bin.000003
Relay_Log_Pos 776942
Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes
Slave_SQL_Running Yes
Replicate_Do_DB
Replicate_Ignore_DB
Replicate_Do_Table
Replicate_Ignore_Table
Replicate_Wild_Do_Table
Replicate_Wild_Ignore_Table
Last_Errno 0
Last_Error
Skip_Counter 0
Exec_Master_Log_Pos 776796
Relay_Log_Space 777097
Until_Condition None
Until_Log_File
Until_Log_Pos 0
Master_SSL_Allowed No
Master_SSL_CA_File
Master_SSL_CA_Path
Master_SSL_Cert
Master_SSL_Cipher
Master_SSL_Key
Seconds_Behind_Master 0
Master_SSL_Verify_Server_Cert No
Last_IO_Errno 0
Last_IO_Error
Last_SQL_Errno 0
Last_SQL_Error
SELECT count(*) "Slave norm" FROM test.regular_tbl;
Slave norm 500
SELECT count(*) "Slave bykey" FROM test.bykey_tbl;
Slave bykey 811
SELECT count(*) "Slave byrange" FROM test.byrange_tbl;
Slave byrange 996
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
use test;
CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE='innodb';
CREATE PROCEDURE test.proc_norm()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.regular_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.regular_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CALL test.proc_norm();
--innodb --innodb_autoinc_lock_mode=0
--innodb --innodb_autoinc_lock_mode=0
--source include/have_innodb.inc
--source include/master-slave.inc
# Set the default connection to 'master'
--vertical_results
let $engine_type= 'innodb';
###### CLEAN UP SECTION ##############
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
######## Creat Table Section #########
use test;
eval CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE=$engine_type;
eval CREATE TABLE test.bykey_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE=$engine_type
PARTITION BY KEY(id) partitions 5;
eval CREATE TABLE test.byrange_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE=$engine_type
PARTITION BY RANGE(id)
SUBPARTITION BY hash(id) subpartitions 2
(PARTITION pa1 values less than (10),
PARTITION pa2 values less than (20),
PARTITION pa3 values less than (30),
PARTITION pa4 values less than (40),
PARTITION pa5 values less than (50),
PARTITION pa6 values less than (60),
PARTITION pa7 values less than (70),
PARTITION pa8 values less than (80),
PARTITION pa9 values less than (90),
PARTITION pa10 values less than (100),
PARTITION pa11 values less than MAXVALUE);
######## Create SPs, Functions, Views and Triggers Section ##############
delimiter |;
CREATE PROCEDURE test.proc_norm()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.regular_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.regular_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CREATE PROCEDURE test.proc_bykey()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.bykey_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.bykey_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.bykey_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
CREATE PROCEDURE test.proc_byrange()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user = CURRENT_USER();
SET local_uuid=UUID();
WHILE ins_count > 0 DO
INSERT INTO test.byrange_tbl VALUES (NULL, NOW(), USER(), UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.byrange_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.byrange_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
delimiter ;|
############ Finish Setup Section ###################
############ Test Section ###################
CALL test.proc_norm();
SELECT count(*) as "Master regular" FROM test.regular_tbl;
CALL test.proc_bykey();
SELECT count(*) as "Master bykey" FROM test.bykey_tbl;
CALL test.proc_byrange();
SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
--sync_slave_with_master
connection slave;
show create table test.byrange_tbl;
show slave status;
SELECT count(*) "Slave norm" FROM test.regular_tbl;
SELECT count(*) "Slave bykey" FROM test.bykey_tbl;
SELECT count(*) "Slave byrange" FROM test.byrange_tbl;
--source include/master-slave-end.inc
connection master;
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
--source include/have_innodb.inc
--source include/master-slave.inc
# Set the default connection to 'master'
--vertical_results
#let $engine_type= 'myisam';
let $engine_type= 'innodb';
###### CLEAN UP SECTION ##############
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
######## Creat Table Section #########
use test;
eval CREATE TABLE test.regular_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE=$engine_type;
######## Create SPs, Functions, Views and Triggers Section ##############
delimiter |;
CREATE PROCEDURE test.proc_norm()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.regular_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.regular_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.regular_tbl WHERE id = del_count;
SET del_count = del_count - 2;
END WHILE;
END|
delimiter ;|
############ Finish Setup Section ###################
############ Test Section ###################
CALL test.proc_norm();
#--source include/master-slave-end.inc
--sync_slave_with_master
connection slave;
......@@ -1904,12 +1904,11 @@ innobase_commit(
/* We just mark the SQL statement ended and do not do a
transaction commit */
if (trx->auto_inc_lock) {
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
row_unlock_table_autoinc_for_mysql(trx);
}
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
SQL statement */
......@@ -1962,13 +1961,11 @@ innobase_rollback(
innobase_release_stat_resources(trx);
if (trx->auto_inc_lock) {
/* If we had reserved the auto-inc lock for some table (if
we come here to roll back the latest SQL statement) we
release it now before a possibly lengthy rollback */
row_unlock_table_autoinc_for_mysql(trx);
}
if (all
|| !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
......@@ -2002,13 +1999,11 @@ innobase_rollback_trx(
innobase_release_stat_resources(trx);
if (trx->auto_inc_lock) {
/* If we had reserved the auto-inc lock for some table (if
we come here to roll back the latest SQL statement) we
release it now before a possibly lengthy rollback */
row_unlock_table_autoinc_for_mysql(trx);
}
error = trx_rollback_for_mysql(trx);
......@@ -7135,6 +7130,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
int mysql_error = 0;
dict_table_t* innodb_table = prebuilt->table;
ibool trx_was_not_started = FALSE;
ulint error;
ut_a(prebuilt);
ut_a(prebuilt->table);
......@@ -7155,7 +7151,11 @@ ha_innobase::innobase_read_and_init_auto_inc(
trx_search_latch_release_if_reserved(prebuilt->trx);
dict_table_autoinc_lock(prebuilt->table);
error = innobase_autoinc_lock();
if (error != DB_SUCCESS) {
mysql_error = 1;
goto err;
}
auto_inc = dict_table_autoinc_read(prebuilt->table);
......@@ -7168,7 +7168,6 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (auto_inc == 0) {
dict_index_t* index;
ulint error = DB_SUCCESS;
const char* autoinc_col_name;
ut_a(!innodb_table->autoinc_inited);
......@@ -7196,6 +7195,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
dict_table_autoinc_unlock(prebuilt->table);
err:
/* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we commit our
transaction here if it was started here. This is to eliminate a
......@@ -7240,12 +7240,10 @@ ha_innobase::innobase_get_auto_increment(
trx = prebuilt->trx;
dict_table_autoinc_unlock(prebuilt->table);
if (trx->auto_inc_lock) {
/* If we had reserved the AUTO-INC
lock in this SQL statement we release
it before retrying.*/
row_unlock_table_autoinc_for_mysql(trx);
}
/* Just to make sure */
ut_a(!trx->auto_inc_lock);
......@@ -7287,6 +7285,7 @@ ha_innobase::get_auto_increment(
ulonglong *first_value, /* out: the autoinc value */
ulonglong *nb_reserved_values) /* out: count of reserved values */
{
trx_t* trx;
ulint error;
ulonglong autoinc = 0;
......@@ -7313,37 +7312,29 @@ ha_innobase::get_auto_increment(
this method for the same statement results in different values which
don't make sense. Therefore we store the value the first time we are
called and count down from that as rows are written (see write_row()).
*/
We make one exception, if the *first_value is precomputed by MySQL
we use that value. And set the number of reserved values to 1 if
this is the first time we were called for the SQL statement, this
will force MySQL to call us for the next value. If we are in the
middle of a multi-row insert we preserve the existing counter.*/
if (*first_value == 0) {
trx = prebuilt->trx;
/* Called for the first time ? */
if (prebuilt->trx->n_autoinc_rows == 0) {
if (trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = (ulint) nb_desired_values;
trx->n_autoinc_rows = nb_desired_values;
/* It's possible for nb_desired_values to be 0:
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
if (nb_desired_values == 0) {
++prebuilt->trx->n_autoinc_rows;
}
trx->n_autoinc_rows = 1;
}
*first_value = autoinc;
} else if (prebuilt->trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = 1;
/* Not in the middle of a mult-row INSERT. */
} else if (prebuilt->last_value == 0) {
*first_value = autoinc;
}
ut_a(prebuilt->trx->n_autoinc_rows > 0);
*nb_reserved_values = prebuilt->trx->n_autoinc_rows;
*nb_reserved_values = trx->n_autoinc_rows;
/* With old style AUTOINC locking we only update the table's
AUTOINC counter after attempting to insert the row. */
......@@ -7670,12 +7661,10 @@ innobase_xa_prepare(
/* We just mark the SQL statement ended and do not do a
transaction prepare */
if (trx->auto_inc_lock) {
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
row_unlock_table_autoinc_for_mysql(trx);
}
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
......@@ -8026,7 +8015,7 @@ static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path,
NULL, NULL, NULL);
static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
PLUGIN_VAR_RQCMDARG,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The AUTOINC lock modes supported by InnoDB:\n"
" 0 => Old style AUTOINC locking (for backward compatibility)\n"
" 1 => New style AUTOINC locking\n"
......
......@@ -4533,7 +4533,6 @@ row_search_autoinc_read_column(
ibool unsigned_type) /* in: signed or unsigned flag */
{
ulint len;
byte* ptr;
const byte* data;
ib_longlong value;
mem_heap_t* heap = NULL;
......@@ -4555,49 +4554,20 @@ row_search_autoinc_read_column(
ut_a(len != UNIV_SQL_NULL);
ut_a(len <= sizeof value);
#ifdef WORDS_BIGENDIAN
/* Copy integer data and restore sign bit */
if (unsigned_type || (data[0] & 128))
memset(dest, 0x00, sizeof(dest));
else
memset(dest, 0xff, sizeof(dest));
memcpy((ptr = dest), data, len);
if (!unsigned_type) {
dest[0] ^= 128;
}
#else
/* Convert integer data from Innobase to a little-endian format,
sign bit restored to normal */
for (ptr = dest + len; ptr != dest; ++data) {
--ptr;
*ptr = *data;
}
memcpy(dest + (sizeof(value) - len), data, len);
if (!unsigned_type) {
dest[len - 1] ^= 128;
}
#endif
if (!unsigned_type)
dest[sizeof(value) - len] ^= 128;
/* The assumption here is that the AUTOINC value can't be negative.*/
switch (len) {
case 8:
value = *(ib_longlong*) ptr;
break;
case 4:
value = *(ib_uint32_t*) ptr;
break;
case 2:
value = *(uint16 *) ptr;
break;
case 1:
value = *ptr;
break;
default:
ut_error;
}
value = (((ib_longlong) mach_read_from_4(dest)) << 32) |
((ib_longlong) mach_read_from_4(dest + 4));
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment