[fix][mds] Make crontab lifecycle safe; simplify scheduling - #1120
Merged
Merged
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical deployment configuration issues and moderate workflow/test issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 2
Open (4)
What changed in this PR
Refactors MDS crontab shutdown for safe lifecycle management and consolidates development deployment scripts.
Changes:
- Adds reservation-based
Stop()/Join()scheduling lifecycle. - Updates callbacks and lifecycle tests.
- Replaces split MDS scripts with
operate_mds.sh. - Adds configurable deployment and logging settings.
| File | Summary |
|---|---|
test/unit/mds/common/test_crontab.cc |
Lifecycle tests; assertions still reference removed pause field. |
src/mds/server.cc |
Updates crontab callback signatures. |
src/mds/common/crontab.h |
Adds lifecycle-safe scheduling API. |
src/mds/common/crontab.cc |
Implements reservation-based shutdown and joining. |
src/client/vfs/metasystem/mds/metasystem.cc |
Updates callback signatures. |
src/client/vfs/metasystem/local/metasystem.cc |
Updates callback signatures. |
scripts/dev-mds/stop_mds.sh |
Superseded by consolidated operations script. |
scripts/dev-mds/start_mds.sh |
Superseded by consolidated operations script. |
scripts/dev-mds/start_client.sh |
Adds configurable logging flags. |
scripts/dev-mds/start_cache.sh |
Adds configurable logging flags. |
scripts/dev-mds/operate_mds.sh |
Consolidates operations; config rendering defaults and multi-process waiting need fixes. |
scripts/dev-mds/mds.template.conf |
Adds logging placeholders; variable names do not match substitutions. |
scripts/dev-mds/env.example |
Adds environment template; documented consumers still use the removed filename. |
scripts/dev-mds/deploy_mds.sh |
Superseded by consolidated operations script. |
scripts/dev-mds/clean_start.sh |
Superseded by consolidated operations script. |
.gitignore |
Ignores local environment configuration. |
.agents/skills/dev-deploy/SKILL.md |
Updates deployment workflow documentation. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+30
to
+31
| --log_level=$MDS_LOG_LEVEL | ||
| --log_v=$MDS_LOG_V |
|
|
||
| DEFINE_integer server_num 3 'server number' | ||
| DEFINE_boolean clean_log true 'clean log' | ||
| DEFINE_boolean replace_conf false 'replace conf' |
| DEFINE_integer server_num 3 'server number' | ||
| DEFINE_boolean clean_log true 'clean log' | ||
| DEFINE_boolean replace_conf false 'replace conf' | ||
| DEFINE_string parameters 'env.local' 'deploy parameters file' |
| EXPECT_EQ(view[0]["interval_ms"].asInt64(), 1000); | ||
| EXPECT_EQ(view[0]["max_times"].asUInt(), 7u); | ||
| EXPECT_EQ(view[0]["immediately"].asBool(), false); | ||
| EXPECT_EQ(view[0]["pause"].asBool(), false); |
rock-git
force-pushed
the
fix/main_092101
branch
from
September 21, 2026 09:17
20b85eb to
748fcae
Compare
StoreAutoIncrementIdGenerator::Stop() deleted the persisted counter key, so every graceful MDS shutdown reset the global id generators (fs id, slice id, ...) back to their start id. After a restart the fs id generator re-issued ids that were still in use, and CreateFs reported the collision as a misleading "fs(name) exist." even though the name did not exist. Stop() now only marks the generator unusable. DestroyId() is public and is called explicitly by DestroyInodeIdGenerator, the only caller that really needs to drop a counter (the filesystem owning it is gone). CreateFs also skips already-used ids when it allocates one itself, and reports an explicitly requested id collision as "fs id(N) exist." instead of reusing the name-exists message.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Sep 21, 2026
rock-git
force-pushed
the
fix/main_092101
branch
from
September 21, 2026 14:51
43e6320 to
321dac7
Compare
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Sep 21, 2026
create_fs.sh defaulted the mds address from SERVER_HOST/SERVER_START_PORT after sourcing the env file; move the source up so the defaults are actually available.
rock-git
force-pushed
the
fix/main_092101
branch
from
September 22, 2026 02:18
321dac7 to
07e0179
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Crontab tasks could outlive their owner during shutdown. The old
CrontabManager::Stop()papered over this with polling: it flipped apauseflag, then loopedbthread_timer_delwithbthread_usleep(1000)until each timer disappeared, and separately waited on an in-flight async counter. Timer callbacks rescheduled themselves from a rawCrontab*, so any cancellation window that was missed became a use-after-free against freed memory.Each
Crontabnow has an explicitStop()/Join()lifecycle backed by reservation counting. A timer or a dispatched bthread holds a reservation until it finishes, andJoin()blocks on a condition variable until the count drains. There is no pause flag, no sleep-poll, and no raw-pointer reschedule.The MDS dev lifecycle scripts ship in the same branch: verifying this path meant redeploying MDS repeatedly, and the four-way split was getting in the way.
Changes
Scheduling model (
src/mds/common/crontab.{h,cc})CrontabConfiggainsmax_timesandimmediately;callbackis nowstd::function<void()>instead ofvoid(void*).AddCrontabtakes configs by value and owns them, so callers no longer keep a live reference for the task's lifetime.ArmLocked()reserves a pending op before publishing the timer. Only a successfulbthread_timer_delor the timer callback itself returns the reservation, so a timer can never fire against a task thatJoin()already observed as drained.run_count_is incremented at invocation admission, before the callback runs. Queued bthreads therefore can't overshootmax_times, and a throwing callback still counts.AddCrontabafterStop()is a no-op.Stop()is safe to call concurrently; it snapshots the task list, stops all tasks, then joins them.CrontabManageruses onebthread_mutex_tplus a vector of tasks; the id map and per-crontab pause/timer bookkeeping are gone.DescribeByJsonreportsstopinstead ofpause, andimmediatelynow reflects configuration rather than mutable run state.Callers
src/mds/server.ccand both client metasystems (local,mds) drop the unusedvoid*parameter from their crontab callbacks.Dev scripts (
scripts/dev-mds/)clean_start.sh,deploy_mds.sh,start_mds.sh,stop_mds.shcollapse intooperate_mds.sh {stop|deploy|start|restart}.restartaborts if stop or deploy fails rather than starting half-broken.mds_deploy_parametersbecomesenv.example.env.localis the local override and is gitignored; it holds host-specific values and credentials.mds.template.confrenders log level/verbosity from$MDS_LOG_LEVEL/$MDS_LOG_V;start_client.shandstart_cache.shexpose--log_level/--log_vflags instead of hardcoding them.Tests
test/unit/mds/common/test_crontab.ccis rewritten around the new lifecycle: stop/join ordering,max_timesunder async overlap, throw handling, and add-after-stop.Test plan
./build/bin/test/test_mds --gtest_filter='*Crontab*'Plus a full build with
-DBUILD_UNIT_TESTS=ONand an MDS restart viabash scripts/dev-mds/operate_mds.sh restart.