-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chunkserver: added clean chunk feature #322
Conversation
@@ -163,6 +163,10 @@ chunkfilepool.chunk_file_pool_dir=./0/ | |||
chunkfilepool.cpmeta_file_size=4096 | |||
# chunkfilepool get chunk最大重试次数 | |||
chunkfilepool.retry_times=5 | |||
# Enable clean chunk | |||
chunkfilepool.clean.enable=true | |||
# The throttle iops for cleaning chunk (4KB/IO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IO size should be configurable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
In my origin design, i think the IO size is as small as better to reduce effect for user's IO request. if we want control the speed of cleaning, we can increase the limited iops.
LOG(ERROR) << "File format version incompatible." | ||
<< "file version: " | ||
<< static_cast<uint32_t>(version) | ||
<< ", format version: " | ||
<< static_cast<uint32_t>(FORMAT_VERSION); | ||
<< ", format version: [" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be valid version
is better, and the statis_cast
is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -189,7 +192,14 @@ CSErrorCode CSChunkFile::Open(bool createFile) { | |||
char buf[pageSize_]; // NOLINT | |||
memset(buf, 0, sizeof(buf)); | |||
metaPage_.encode(buf); | |||
int rc = chunkFilePool_->GetFile(chunkFilePath, buf); | |||
|
|||
auto updateMetapageCb = [this](char* buffer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can just update default version from FORMAT_VERSION
to FORMAT_VERSION_V2
in ChunkFileMetaPage's constructor. And, remove this callback to update version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't gurantee get clean chunk success in every operation, so if we get dirty chunk we should use FORMAT_VERSION
in metapage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't gurantee get clean chunk success in every operation, so if we get dirty chunk we should use
FORMAT_VERSION
in metapage.
I think you will get a clean chunk if you set needClean
to true when calling GetChunk
.
And after GetChunk
returned with true, you got a cleaned chunk even if the chunk is from dirty pool, because you did fallocate it with FALLOC_FL_ZERO_RANGE
. And for FALLOC_FL_ZERO_RANGE
, it will mark the file as unwritten, so read from this file is just like a clean chunk file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wu-hanqing done
std::string chunkpath = currentdir_ + "/" + std::to_string(chunkid); | ||
int ret = fsptr_->Open(chunkpath.c_str(), O_RDWR); | ||
if (ret < 0) { | ||
LOG(ERROR) << "Open file failed: " << chunkpath.c_str(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.c_str()
is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
uint64_t chunklen = poolOpt_.fileSize + poolOpt_.metaPageSize; | ||
if (onlyMarked) { | ||
ret = fsptr_->Fallocate(fd, FALLOC_FL_ZERO_RANGE, 0, chunklen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does FALLOC_FL_KEEP_SIZE
flag is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The chunklen
is fixed, I think we don't need this flag.
auto popBack = [this](std::vector<uint64_t>& chunks, | ||
uint64_t& chunksLeft) -> uint64_t { | ||
std::unique_lock<std::mutex> lk(mtx_); | ||
if (0 == chunks.size()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check whether a vector is empty, just use .empty()
member function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -35,6 +35,7 @@ namespace chunkserver { | |||
using curve::common::Bitmap; | |||
|
|||
const uint8_t FORMAT_VERSION = 1; | |||
const uint8_t FORMAT_VERSION_V2 = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add some annotation to explain the meaning of each version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
private: | ||
// Protect tmpChunkvec_ | ||
// The suffix of clean chunk file (".0") | ||
static const char* kCleanChunkSuffix_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just define as std::string, so static std::string GetCleanChunkSuffix()
no need to convert from const char* to std::string.
And, I think .clean
suffix is more meaningful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
YES, i think it's better to use .clean
suffix.
} | ||
|
||
uint64_t FilePool::GetChunk(bool needClean, bool* isCleaned) { | ||
auto smartPop = [this](std::vector<uint64_t>& chunks1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This lambda a little bit complex. It better to define two member functions, e.g., Push
and Pop
, and each one takes one argument to determine whether push/pop from dirty pool or clean pool.
By the way, if the function going to change the argument, it should task a pointer instead of a non-const reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
std::unique_lock<std::mutex> lk(mtx_); | ||
if (tmpChunkvec_.empty()) { | ||
LOG(ERROR) << "no avaliable chunk!"; | ||
chunkID = GetChunk(needClean, &isCleaned); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether exist a chunk which id is 0, so it's better to let chunkID as an argument and check by the return value(true/false).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
yeap, the valid chunk id start with 1
All review suggestions had been implemented @wu-hanqing |
@@ -131,6 +131,9 @@ chunkserver_rconcurrentapply_queuedepth: 1 | |||
chunkserver_chunkfilepool_chunk_file_pool_dir: ./0/ | |||
chunkserver_chunkfilepool_cpmeta_file_size: 4096 | |||
chunkserver_chunkfilepool_retry_times: 5 | |||
chunkserver_chunkfilepool_clean_enable: true | |||
chunkserver_chunkfilepool_clean_bytes_per_write: 4096 | |||
chunkserver_chunkfilepool_clean_throttle_iops: 500 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in chunkserver.conf it is 2000, why here 500?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SeanHai I will unify them.
return true; | ||
} | ||
|
||
void FilePool::CleanWorker() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how to clean the dirty chunks already in chunkfilepool?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
std::unique_lock<std::mutex> lk(mtx_); | ||
tmpChunkvec_.push_back(newfilenum); | ||
++currentState_.preallocatedChunksLeft; | ||
dirtyChunks_.push_back(newfilenum); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the chunkserver crashed, will the recycled dirty chunks missed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SeanHai No, the recycled dirty chunks already in the chunkfile directory, the dirtyChunks_
vector is only hold the chunk's number in memory.
src/chunkserver/chunkserver.cpp
Outdated
LOG_IF(FATAL, !conf->GetUInt32Value("chunkfilepool.clean.throttle_iops", | ||
&chunkFilePoolOptions->iops4clean)); | ||
|
||
if (chunkFilePoolOptions->bytesPerWrite < 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have defined chunkFilePoolOptions->bytesPerWrite
as unsigned int, so it cannot less than 0.
And, I think bytesPerWrite
should be aligned to 4K.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
memset(buffer, 0, kBytesPerWrite_); | ||
uint32_t bytesPerWrite = poolOpt_.bytesPerWrite; | ||
|
||
char *buffer = new (std::nothrow) char[bytesPerWrite]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forget free this space, and I think buffer can be a member variable, so you don't have to frequently new/delete it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wu-hanqing done
@@ -202,7 +207,9 @@ class CURVE_CACHELINE_ALIGNMENT FilePool { | |||
/** | |||
* @brief: Return the suffix of clean chunk | |||
*/ | |||
static std::string GetCleanChunkSuffix(); | |||
inline static std::string GetCleanChunkSuffix() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keyword inline
is redundant because member functions defined in header files are implicit inline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wu-hanqing done.
bool ret = pop(&cleanChunks_, ¤tState_.cleanChunksLeft, true) | ||
|| pop(&dirtyChunks_, ¤tState_.dirtyChunksLeft, false); | ||
|
||
if (false == *isCleaned && CleanChunk(*chunkid, true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should also test ret is true or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wu-hanqing done.
@@ -189,7 +192,14 @@ CSErrorCode CSChunkFile::Open(bool createFile) { | |||
char buf[pageSize_]; // NOLINT | |||
memset(buf, 0, sizeof(buf)); | |||
metaPage_.encode(buf); | |||
int rc = chunkFilePool_->GetFile(chunkFilePath, buf); | |||
|
|||
auto updateMetapageCb = [this](char* buffer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't gurantee get clean chunk success in every operation, so if we get dirty chunk we should use
FORMAT_VERSION
in metapage.
I think you will get a clean chunk if you set needClean
to true when calling GetChunk
.
And after GetChunk
returned with true, you got a cleaned chunk even if the chunk is from dirty pool, because you did fallocate it with FALLOC_FL_ZERO_RANGE
. And for FALLOC_FL_ZERO_RANGE
, it will mark the file as unwritten, so read from this file is just like a clean chunk file.
@@ -199,7 +204,9 @@ FilePool::FilePool(std::shared_ptr<LocalFileSystem> fsptr) | |||
: currentmaxfilenum_(0) { | |||
CHECK(fsptr != nullptr) << "fs ptr allocate failed!"; | |||
fsptr_ = fsptr; | |||
tmpChunkvec_.clear(); | |||
cleanAlived_ = false; | |||
dirtyChunks_.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to clear it, it's empty by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wu-hanqing In some test case, it will call the UnInitialize()
to do some clear work, and expect to clear these vectors.
InterruptibleSleeper cleanSleeper_; | ||
|
||
// The buffer for write chunk file | ||
std::shared_ptr<char> writeBuffer_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::unique_ptr<char[]>
is more suitable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::unique_ptr<char[]>
is more suitable.
done.
@@ -188,8 +187,10 @@ CSErrorCode CSChunkFile::Open(bool createFile) { | |||
&& metaPage_.sn > 0) { | |||
char buf[pageSize_]; // NOLINT | |||
memset(buf, 0, sizeof(buf)); | |||
metaPage_.version = FORMAT_VERSION_V2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this version in MetaPage's constructor is better, but some unit tests may be affected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this version in MetaPage's constructor is better, but some unit tests may be affected.
When chunkserver start, it will scan all chunk files in the copyset directory, and these chunk files is not clean. so if we change the version in MetaPage's constructor, these dirty chunk files will cause confuse.
Add TiKV 2021 spring proposal
What problem does this PR solve?
Issue Number: close #xxx
Problem Summary:
What is changed and how it works?
What's Changed:
How it Works:
Side effects(Breaking backward compatibility? Performance regression?):
Check List