Commit 6b687a0f authored by Marko Mäkelä's avatar Marko Mäkelä

Introduce page_rec_is_leaf() and clean up page0page.h

Define some page accessor functions inline in page0page.h,
reducing code duplication in page0page.ic.

Use page_rec_is_leaf() instead of page_is_leaf() where possible.
parent 77b241eb
......@@ -832,7 +832,7 @@ btr_node_ptr_set_child_page_no(
ulint len;
ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_ad(!page_is_leaf(page_align(rec)));
ut_ad(!page_rec_is_leaf(rec));
ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
/* The child address is in the last field */
......
......@@ -4665,7 +4665,7 @@ btr_cur_del_mark_set_clust_rec(
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
ut_ad(buf_block_get_frame(block) == page_align(rec));
ut_ad(page_is_leaf(page_align(rec)));
ut_ad(page_rec_is_leaf(rec));
ut_ad(mtr->is_named_space(index->space));
if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
......
......@@ -5685,7 +5685,7 @@ dict_index_copy_rec_order_prefix(
ut_a(!dict_table_is_comp(index->table));
n = rec_get_n_fields_old(rec);
} else {
if (page_is_leaf(page_align(rec))) {
if (page_rec_is_leaf(rec)) {
n = dict_index_get_n_unique_in_tree(index);
} else {
n = dict_index_get_n_unique_in_tree_nonleaf(index);
......
......@@ -167,25 +167,196 @@ directory. */
#define PAGE_DIR_SLOT_MIN_N_OWNED 4
extern my_bool srv_immediate_scrub_data_uncompressed;
#endif /* UNIV_INNOCHECKSUM */
/************************************************************//**
Gets the start of a page.
@return start of the page */
UNIV_INLINE
/** Get the start of a page frame.
@param[in] ptr pointer within a page frame
@return start of the page frame */
MY_ATTRIBUTE((const))
inline
page_t*
page_align(
/*=======*/
const void* ptr) /*!< in: pointer to page frame */
MY_ATTRIBUTE((const));
/************************************************************//**
Gets the offset within a page.
page_align(const void* ptr)
{
return(static_cast<page_t*>(ut_align_down(ptr, UNIV_PAGE_SIZE)));
}
/** Gets the byte offset within a page frame.
@param[in] ptr pointer within a page frame
@return offset from the start of the page */
UNIV_INLINE
MY_ATTRIBUTE((const))
inline
ulint
page_offset(
/*========*/
const void* ptr) /*!< in: pointer to page frame */
MY_ATTRIBUTE((const));
page_offset(const void* ptr)
{
return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
}
/** Determine whether an index page is not in ROW_FORMAT=REDUNDANT.
@param[in] page index page
@return nonzero if ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED
@retval 0 if ROW_FORMAT=REDUNDANT */
inline
byte
page_is_comp(const page_t* page)
{
ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN));
return(page[PAGE_HEADER + PAGE_N_HEAP] & 0x80);
}
/** Determine whether an index page is empty.
@param[in] page index page
@return whether the page is empty (PAGE_N_RECS = 0) */
inline
bool
page_is_empty(const page_t* page)
{
ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN));
return !*reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_N_RECS
+ page);
}
/** Determine whether an index page contains garbage.
@param[in] page index page
@return whether the page contains garbage (PAGE_GARBAGE is not 0) */
inline
bool
page_has_garbage(const page_t* page)
{
ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN));
return *reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_GARBAGE
+ page);
}
/** Determine whether an B-tree or R-tree index page is a leaf page.
@param[in] page index page
@return true if the page is a leaf (PAGE_LEVEL = 0) */
inline
bool
page_is_leaf(const page_t* page)
{
ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN));
return !*reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_LEVEL
+ page);
}
#ifndef UNIV_INNOCHECKSUM
/** Determine whether an index page record is not in ROW_FORMAT=REDUNDANT.
@param[in] rec record in an index page frame (not a copy)
@return nonzero if ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED
@retval 0 if ROW_FORMAT=REDUNDANT */
inline
byte
page_rec_is_comp(const byte* rec)
{
return(page_is_comp(page_align(rec)));
}
/** Determine the offset of the infimum record on the page.
@param[in] page index page
@return offset of the infimum record in record list, relative from page */
inline
unsigned
page_get_infimum_offset(const page_t* page)
{
ut_ad(!page_offset(page));
return page_is_comp(page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM;
}
/** Determine the offset of the supremum record on the page.
@param[in] page index page
@return offset of the supremum record in record list, relative from page */
inline
unsigned
page_get_supremum_offset(const page_t* page)
{
ut_ad(!page_offset(page));
return page_is_comp(page) ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM;
}
/** Determine whether an index page record is a user record.
@param[in] offset record offset in the page
@retval true if a user record
@retval false if the infimum or supremum pseudo-record */
inline
bool
page_rec_is_user_rec_low(ulint offset)
{
compile_time_assert(PAGE_OLD_INFIMUM >= PAGE_NEW_INFIMUM);
compile_time_assert(PAGE_OLD_SUPREMUM >= PAGE_NEW_SUPREMUM);
compile_time_assert(PAGE_NEW_INFIMUM < PAGE_OLD_SUPREMUM);
compile_time_assert(PAGE_OLD_INFIMUM < PAGE_NEW_SUPREMUM);
compile_time_assert(PAGE_NEW_SUPREMUM < PAGE_OLD_SUPREMUM_END);
compile_time_assert(PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM_END);
ut_ad(offset >= PAGE_NEW_INFIMUM);
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset != PAGE_NEW_SUPREMUM
&& offset != PAGE_NEW_INFIMUM
&& offset != PAGE_OLD_INFIMUM
&& offset != PAGE_OLD_SUPREMUM);
}
/** Determine if a record is the supremum record on an index page.
@param[in] offset record offset in an index page
@return true if the supremum record */
inline
bool
page_rec_is_supremum_low(ulint offset)
{
ut_ad(offset >= PAGE_NEW_INFIMUM);
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset == PAGE_NEW_SUPREMUM || offset == PAGE_OLD_SUPREMUM);
}
/** Determine if a record is the infimum record on an index page.
@param[in] offset record offset in an index page
@return true if the infimum record */
inline
bool
page_rec_is_infimum_low(ulint offset)
{
ut_ad(offset >= PAGE_NEW_INFIMUM);
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset == PAGE_NEW_INFIMUM || offset == PAGE_OLD_INFIMUM);
}
/** Determine whether an B-tree or R-tree index record is in a leaf page.
@param[in] rec index record in an index page
@return true if the record is in a leaf page */
inline
bool
page_rec_is_leaf(const page_t* rec)
{
const page_t* page = page_align(rec);
ut_ad(rec - page >= page_get_infimum_offset(page));
bool leaf = page_is_leaf(page);
ut_ad(!page_rec_is_comp(rec)
|| !page_rec_is_user_rec_low(rec - page)
|| leaf == !rec_get_node_ptr_flag(rec));
return leaf;
}
/** Determine whether an index page record is a user record.
@param[in] rec record in an index page
@return true if a user record */
inline
bool
page_rec_is_user_rec(const rec_t* rec);
/** Determine whether an index page record is the supremum record.
@param[in] rec record in an index page
@return true if the supremum record */
inline
bool
page_rec_is_supremum(const rec_t* rec);
/** Determine whether an index page record is the infimum record.
@param[in] rec record in an index page
@return true if the infimum record */
inline
bool
page_rec_is_infimum(const rec_t* rec);
/*************************************************************//**
Returns the max trx id field value. */
UNIV_INLINE
......@@ -321,22 +492,6 @@ page_header_reset_last_insert(
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
uncompressed part will be updated, or NULL */
mtr_t* mtr); /*!< in: mtr */
/************************************************************//**
Gets the offset of the first record on the page.
@return offset of the first record in record list, relative from page */
UNIV_INLINE
ulint
page_get_infimum_offset(
/*====================*/
const page_t* page); /*!< in: page which must have record(s) */
/************************************************************//**
Gets the offset of the last record on the page.
@return offset of the last record in record list, relative from page */
UNIV_INLINE
ulint
page_get_supremum_offset(
/*=====================*/
const page_t* page); /*!< in: page which must have record(s) */
#define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page))
#define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page))
......@@ -522,23 +677,7 @@ ulint
page_dir_find_owner_slot(
/*=====================*/
const rec_t* rec); /*!< in: the physical record */
/************************************************************//**
Determine whether the page is in new-style compact format.
@return nonzero if the page is in compact format, zero if it is in
old-style format */
UNIV_INLINE
ulint
page_is_comp(
/*=========*/
const page_t* page); /*!< in: index page */
/************************************************************//**
TRUE if the record is on a page in compact format.
@return nonzero if in compact format */
UNIV_INLINE
ulint
page_rec_is_comp(
/*=============*/
const rec_t* rec); /*!< in: record */
/***************************************************************//**
Returns the heap number of a record.
@return heap number */
......@@ -547,24 +686,6 @@ ulint
page_rec_get_heap_no(
/*=================*/
const rec_t* rec); /*!< in: the physical record */
/************************************************************//**
Determine whether the page is a B-tree leaf.
@return true if the page is a B-tree leaf (PAGE_LEVEL = 0) */
UNIV_INLINE
bool
page_is_leaf(
/*=========*/
const page_t* page) /*!< in: page */
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Determine whether the page is empty.
@return true if the page is empty (PAGE_N_RECS = 0) */
UNIV_INLINE
bool
page_is_empty(
/*==========*/
const page_t* page) /*!< in: page */
MY_ATTRIBUTE((warn_unused_result));
/** Determine whether a page is an index root page.
@param[in] page page frame
@return true if the page is a root page of an index */
......@@ -574,15 +695,6 @@ page_is_root(
const page_t* page)
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Determine whether the page contains garbage.
@return true if the page contains garbage (PAGE_GARBAGE is not 0) */
UNIV_INLINE
bool
page_has_garbage(
/*=============*/
const page_t* page) /*!< in: page */
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Gets the pointer to the next record on the page.
@return pointer to next record */
UNIV_INLINE
......@@ -645,62 +757,6 @@ page_rec_get_prev(
/*==============*/
rec_t* rec); /*!< in: pointer to record,
must not be page infimum */
/************************************************************//**
TRUE if the record is a user record on the page.
@return TRUE if a user record */
UNIV_INLINE
ibool
page_rec_is_user_rec_low(
/*=====================*/
ulint offset) /*!< in: record offset on page */
MY_ATTRIBUTE((const));
/************************************************************//**
TRUE if the record is the supremum record on a page.
@return TRUE if the supremum record */
UNIV_INLINE
ibool
page_rec_is_supremum_low(
/*=====================*/
ulint offset) /*!< in: record offset on page */
MY_ATTRIBUTE((const));
/************************************************************//**
TRUE if the record is the infimum record on a page.
@return TRUE if the infimum record */
UNIV_INLINE
ibool
page_rec_is_infimum_low(
/*====================*/
ulint offset) /*!< in: record offset on page */
MY_ATTRIBUTE((const));
/************************************************************//**
TRUE if the record is a user record on the page.
@return TRUE if a user record */
UNIV_INLINE
ibool
page_rec_is_user_rec(
/*=================*/
const rec_t* rec) /*!< in: record */
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
TRUE if the record is the supremum record on a page.
@return TRUE if the supremum record */
UNIV_INLINE
ibool
page_rec_is_supremum(
/*=================*/
const rec_t* rec) /*!< in: record */
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
TRUE if the record is the infimum record on a page.
@return TRUE if the infimum record */
UNIV_INLINE
ibool
page_rec_is_infimum(
/*================*/
const rec_t* rec) /*!< in: record */
MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
true if the record is the first user record on a page.
......
......@@ -40,32 +40,7 @@ Created 2/2/1994 Heikki Tuuri
#undef UNIV_INLINE
#define UNIV_INLINE
#endif
#endif /* !UNIV_INNOCHECKSUM */
/************************************************************//**
Gets the start of a page.
@return start of the page */
UNIV_INLINE
page_t*
page_align(
/*=======*/
const void* ptr) /*!< in: pointer to page frame */
{
return((page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE));
}
#ifndef UNIV_INNOCHECKSUM
/************************************************************//**
Gets the offset within a page.
@return offset from the start of the page */
UNIV_INLINE
ulint
page_offset(
/*========*/
const void* ptr) /*!< in: pointer to page frame */
{
return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
}
/*************************************************************//**
Returns the max trx id field value. */
UNIV_INLINE
......@@ -286,34 +261,6 @@ page_header_reset_last_insert(
}
}
#endif /* !UNIV_INNOCHECKSUM */
/************************************************************//**
Determine whether the page is in new-style compact format.
@return nonzero if the page is in compact format, zero if it is in
old-style format */
UNIV_INLINE
ulint
page_is_comp(
/*=========*/
const page_t* page) /*!< in: index page */
{
return(page[PAGE_HEADER + PAGE_N_HEAP] & 0x80);
}
#ifndef UNIV_INNOCHECKSUM
/************************************************************//**
TRUE if the record is on a page in compact format.
@return nonzero if in compact format */
UNIV_INLINE
ulint
page_rec_is_comp(
/*=============*/
const rec_t* rec) /*!< in: record */
{
return(page_is_comp(page_align(rec)));
}
/***************************************************************//**
Returns the heap number of a record.
@return heap number */
......@@ -330,33 +277,6 @@ page_rec_get_heap_no(
}
}
#endif /* !UNIV_INNOCHECKSUM */
/************************************************************//**
Determine whether the page is a B-tree leaf.
@return true if the page is a B-tree leaf (PAGE_LEVEL = 0) */
UNIV_INLINE
bool
page_is_leaf(
/*=========*/
const page_t* page) /*!< in: page */
{
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
}
#ifndef UNIV_INNOCHECKSUM
/************************************************************//**
Determine whether the page is empty.
@return true if the page is empty (PAGE_N_RECS = 0) */
UNIV_INLINE
bool
page_is_empty(
/*==========*/
const page_t* page) /*!< in: page */
{
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_N_RECS)));
}
/** Determine whether a page is an index root page.
@param[in] page page frame
@return true if the page is a root page of an index */
......@@ -382,162 +302,36 @@ page_is_root(
== IB_UINT64_MAX);
}
/************************************************************//**
Determine whether the page contains garbage.
@return true if the page contains garbage (PAGE_GARBAGE is not 0) */
UNIV_INLINE
/** Determine whether an index page record is a user record.
@param[in] rec record in an index page
@return true if a user record */
inline
bool
page_has_garbage(
/*=============*/
const page_t* page) /*!< in: page */
{
return(!!*(const uint16*) (page + (PAGE_HEADER + PAGE_GARBAGE)));
}
/************************************************************//**
Gets the offset of the first record on the page.
@return offset of the first record in record list, relative from page */
UNIV_INLINE
ulint
page_get_infimum_offset(
/*====================*/
const page_t* page) /*!< in: page which must have record(s) */
{
ut_ad(page);
ut_ad(!page_offset(page));
if (page_is_comp(page)) {
return(PAGE_NEW_INFIMUM);
} else {
return(PAGE_OLD_INFIMUM);
}
}
/************************************************************//**
Gets the offset of the last record on the page.
@return offset of the last record in record list, relative from page */
UNIV_INLINE
ulint
page_get_supremum_offset(
/*=====================*/
const page_t* page) /*!< in: page which must have record(s) */
{
ut_ad(page);
ut_ad(!page_offset(page));
if (page_is_comp(page)) {
return(PAGE_NEW_SUPREMUM);
} else {
return(PAGE_OLD_SUPREMUM);
}
}
/************************************************************//**
TRUE if the record is a user record on the page.
@return TRUE if a user record */
UNIV_INLINE
ibool
page_rec_is_user_rec_low(
/*=====================*/
ulint offset) /*!< in: record offset on page */
{
ut_ad(offset >= PAGE_NEW_INFIMUM);
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
#endif
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
#endif
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
#endif
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
#endif
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
#endif
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
#endif
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset != PAGE_NEW_SUPREMUM
&& offset != PAGE_NEW_INFIMUM
&& offset != PAGE_OLD_INFIMUM
&& offset != PAGE_OLD_SUPREMUM);
}
/************************************************************//**
TRUE if the record is the supremum record on a page.
@return TRUE if the supremum record */
UNIV_INLINE
ibool
page_rec_is_supremum_low(
/*=====================*/
ulint offset) /*!< in: record offset on page */
{
ut_ad(offset >= PAGE_NEW_INFIMUM);
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset == PAGE_NEW_SUPREMUM
|| offset == PAGE_OLD_SUPREMUM);
}
/************************************************************//**
TRUE if the record is the infimum record on a page.
@return TRUE if the infimum record */
UNIV_INLINE
ibool
page_rec_is_infimum_low(
/*====================*/
ulint offset) /*!< in: record offset on page */
{
ut_ad(offset >= PAGE_NEW_INFIMUM);
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
return(offset == PAGE_NEW_INFIMUM || offset == PAGE_OLD_INFIMUM);
}
/************************************************************//**
TRUE if the record is a user record on the page.
@return TRUE if a user record */
UNIV_INLINE
ibool
page_rec_is_user_rec(
/*=================*/
const rec_t* rec) /*!< in: record */
page_rec_is_user_rec(const rec_t* rec)
{
ut_ad(page_rec_check(rec));
return(page_rec_is_user_rec_low(page_offset(rec)));
}
/************************************************************//**
TRUE if the record is the supremum record on a page.
@return TRUE if the supremum record */
UNIV_INLINE
ibool
page_rec_is_supremum(
/*=================*/
const rec_t* rec) /*!< in: record */
/** Determine whether an index page record is the supremum record.
@param[in] rec record in an index page
@return true if the supremum record */
inline
bool
page_rec_is_supremum(const rec_t* rec)
{
ut_ad(page_rec_check(rec));
return(page_rec_is_supremum_low(page_offset(rec)));
}
/************************************************************//**
TRUE if the record is the infimum record on a page.
@return TRUE if the infimum record */
UNIV_INLINE
ibool
page_rec_is_infimum(
/*================*/
const rec_t* rec) /*!< in: record */
/** Determine whether an index page record is the infimum record.
@param[in] rec record in an index page
@return true if the infimum record */
inline
bool
page_rec_is_infimum(const rec_t* rec)
{
ut_ad(page_rec_check(rec));
return(page_rec_is_infimum_low(page_offset(rec)));
}
......
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
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
......@@ -443,10 +444,11 @@ mlog_open_and_write_index(
alloc = mtr_buf_t::MAX_DATA_SIZE;
}
const bool is_leaf = page_is_leaf(page_align(rec));
/* For spatial index, on non-leaf page, we just keep
2 fields, MBR and page no. */
if (dict_index_is_spatial(index)
&& !page_is_leaf(page_align(rec))) {
if (!is_leaf && dict_index_is_spatial(index)) {
n = DICT_INDEX_SPATIAL_NODEPTR_SIZE;
}
......@@ -464,7 +466,7 @@ mlog_open_and_write_index(
mach_write_to_2(log_ptr, n);
log_ptr += 2;
if (page_is_leaf(page_align(rec))) {
if (is_leaf) {
mach_write_to_2(
log_ptr, dict_index_get_n_unique_in_tree(index));
} else {
......
......@@ -873,7 +873,7 @@ page_copy_rec_list_start(
max_trx_id is ignored for temp tables because it not required
for MVCC. */
if (dict_index_is_sec_or_ibuf(index)
&& page_is_leaf(page_align(rec))
&& page_rec_is_leaf(rec)
&& !dict_table_is_temporary(index->table)) {
page_update_max_trx_id(new_block, NULL,
page_get_max_trx_id(page_align(rec)),
......
......@@ -797,7 +797,6 @@ cmp_dtuple_rec_with_match_bytes(
ut_ad(dtuple_check_typed(dtuple));
ut_ad(rec_offs_validate(rec, index, offsets));
//ut_ad(page_is_leaf(page_align(rec)));
ut_ad(!(REC_INFO_MIN_REC_FLAG
& dtuple_get_info_bits(dtuple)));
ut_ad(!(REC_INFO_MIN_REC_FLAG
......
......@@ -972,7 +972,7 @@ row_log_table_low(
&index->lock,
RW_LOCK_FLAG_S | RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX));
ut_ad(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
ut_ad(page_is_leaf(page_align(rec)));
ut_ad(page_rec_is_leaf(rec));
ut_ad(!page_is_comp(page_align(rec)) == !rec_offs_comp(offsets));
/* old_pk=row_log_table_get_pk() [not needed in INSERT] is a prefix
of the clustered index record (PRIMARY KEY,DB_TRX_ID,DB_ROLL_PTR),
......
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