Skip to content

Commit 25c28f8

Browse files
committed
fix(config_compiler): duplicate PendingChild dependencies happen from multiple commands on the same node
1 parent 632cf4b commit 25c28f8

File tree

3 files changed

+46
-14
lines changed

3 files changed

+46
-14
lines changed

src/rime/config/config_compiler.cc

+43-14
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ struct Dependency {
1111
an<ConfigItemRef> target;
1212

1313
virtual bool blocking() const = 0;
14+
virtual string repr() const = 0;
1415
virtual bool Resolve(ConfigCompiler* compiler) = 0;
1516
};
1617

18+
template <class StreamT>
19+
StreamT& operator<< (StreamT& stream, const Dependency& dep) {
20+
return stream << dep.repr() << (dep.blocking() ? "(blocking)" : "");
21+
}
22+
1723
struct PendingChild : Dependency {
1824
string child_path;
1925
an<ConfigItemRef> child_ref;
@@ -24,12 +30,19 @@ struct PendingChild : Dependency {
2430
bool blocking() const override {
2531
return false;
2632
}
33+
string repr() const override {
34+
return "PendingChild(" + child_path + ")";
35+
}
2736
bool Resolve(ConfigCompiler* compiler) override;
2837
};
2938

39+
string Reference::repr() const {
40+
return resource_id + ":" + local_path;
41+
}
42+
3043
template <class StreamT>
3144
StreamT& operator<< (StreamT& stream, const Reference& reference) {
32-
return stream << reference.resource_id << ":" << reference.local_path;
45+
return stream << reference.repr();
3346
}
3447

3548
struct IncludeReference : Dependency {
@@ -38,6 +51,9 @@ struct IncludeReference : Dependency {
3851
bool blocking() const override {
3952
return true;
4053
}
54+
string repr() const override {
55+
return "Include(" + reference.repr() + ")";
56+
}
4157
bool Resolve(ConfigCompiler* compiler) override;
4258

4359
Reference reference;
@@ -49,6 +65,9 @@ struct PatchReference : Dependency {
4965
bool blocking() const override {
5066
return true;
5167
}
68+
string repr() const override {
69+
return "Patch(" + reference.repr() + ")";
70+
}
5271
bool Resolve(ConfigCompiler* compiler) override;
5372

5473
Reference reference;
@@ -62,6 +81,9 @@ struct PatchLiteral : Dependency {
6281
bool blocking() const override {
6382
return true;
6483
}
84+
string repr() const override {
85+
return "Patch(<literal>)";
86+
}
6587
bool Resolve(ConfigCompiler* compiler) override;
6688
};
6789

@@ -107,6 +129,7 @@ bool IncludeReference::Resolve(ConfigCompiler* compiler) {
107129
}
108130

109131
bool PatchReference::Resolve(ConfigCompiler* compiler) {
132+
LOG(INFO) << "PatchReference::Resolve(reference = " << reference << ")";
110133
auto item = ResolveReference(compiler, reference);
111134
if (!item) {
112135
return false;
@@ -125,10 +148,12 @@ bool TraverseCopyOnWrite(an<ConfigItemRef> root, const string& path,
125148
an<ConfigItem> item);
126149

127150
bool PatchLiteral::Resolve(ConfigCompiler* compiler) {
151+
LOG(INFO) << "PatchLiteral::Resolve()";
128152
bool success = true;
129153
for (const auto& entry : *patch) {
130154
const auto& path = entry.first;
131155
const auto& value = entry.second;
156+
LOG(INFO) << "patching " << path;
132157
if (!TraverseCopyOnWrite(target, path, value)) {
133158
LOG(ERROR) << "error applying patch to " << path;
134159
success = false;
@@ -143,25 +168,29 @@ void ConfigDependencyGraph::Add(an<Dependency> dependency) {
143168
const auto& target = node_stack.back();
144169
dependency->target = target;
145170
auto target_path = ConfigData::JoinPath(key_stack);
146-
deps[target_path].push_back(dependency);
147-
LOG(INFO) << "target_path = " << target_path << ", #deps = " << deps[target_path].size();
171+
auto& target_deps = deps[target_path];
172+
bool target_was_pending = !target_deps.empty();
173+
target_deps.push_back(dependency);
174+
LOG(INFO) << "target_path = " << target_path << ", #deps = " << target_deps.size();
175+
if (target_was_pending || // so was all ancestors
176+
key_stack.size() == 1) { // this is the progenitor
177+
return;
178+
}
148179
// The current pending node becomes a prioritized dependency of parent node
149-
auto child = target;
150180
auto keys = key_stack;
151-
for (auto prev = node_stack.rbegin() + 1; prev != node_stack.rend(); ++prev) {
181+
for (auto child = node_stack.rbegin(); child != node_stack.rend(); ++child) {
152182
auto last_key = keys.back();
153183
keys.pop_back();
154184
auto parent_path = ConfigData::JoinPath(keys);
155185
auto& parent_deps = deps[parent_path];
156186
bool parent_was_pending = !parent_deps.empty();
157187
// Pending children should be resolved before applying __include or __patch
158-
parent_deps.push_front(New<PendingChild>(parent_path + "/" + last_key, child));
188+
parent_deps.push_front(New<PendingChild>(parent_path + "/" + last_key, *child));
159189
LOG(INFO) << "parent_path = " << parent_path << ", #deps = " << parent_deps.size();
160-
if (parent_was_pending) {
161-
// so was all ancestors
162-
break;
190+
if (parent_was_pending || // so was all ancestors
191+
keys.size() == 1) { // this parent is the progenitor
192+
return;
163193
}
164-
child = *prev;
165194
}
166195
}
167196

@@ -244,7 +273,7 @@ static bool ResolveBlockingDependencies(ConfigCompiler* compiler,
244273
static an<ConfigItem> GetResolvedItem(ConfigCompiler* compiler,
245274
an<ConfigResource> resource,
246275
const string& path) {
247-
LOG(INFO) << "GetResolvedItem(" << resource->resource_id << ":/" << path << ")";
276+
LOG(INFO) << "GetResolvedItem(" << resource->resource_id << ":" << path << ")";
248277
string node_path = resource->resource_id + ":";
249278
if (!resource || compiler->blocking(node_path)) {
250279
return nullptr;
@@ -364,7 +393,7 @@ static bool ParsePatch(ConfigCompiler* compiler,
364393
}
365394

366395
bool ConfigCompiler::Parse(const string& key, const an<ConfigItem>& item) {
367-
LOG(INFO) << "ConfigCompiler::Parse(" << key << ")";
396+
DLOG(INFO) << "ConfigCompiler::Parse(" << key << ")";
368397
if (key == INCLUDE_DIRECTIVE) {
369398
return ParseInclude(this, item);
370399
}
@@ -389,10 +418,10 @@ bool ConfigCompiler::ResolveDependencies(const string& path) {
389418
auto& deps = graph_->deps[path];
390419
for (auto iter = deps.begin(); iter != deps.end(); ) {
391420
if (!(*iter)->Resolve(this)) {
392-
LOG(INFO) << "unesolved dependency!";
421+
LOG(ERROR) << "unesolved dependency:" << **iter;
393422
return false;
394423
}
395-
LOG(INFO) << "resolved.";
424+
LOG(INFO) << "resolved " << **iter;
396425
iter = deps.erase(iter);
397426
}
398427
LOG(INFO) << "all dependencies resolved.";

src/rime/config/config_compiler.h

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ struct ConfigResource : ConfigItemRef {
2929
struct Reference {
3030
string resource_id;
3131
string local_path;
32+
33+
string repr() const;
3234
};
3335

3436
class ResourceResolver;

src/rime/config/config_data.cc

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class ConfigListEntryCowRef : public ConfigMapEntryCowRef {
207207

208208
bool TraverseCopyOnWrite(an<ConfigItemRef> root, const string& path,
209209
an<ConfigItem> item) {
210+
LOG(INFO) << "TraverseCopyOnWrite(" << path << ")";
210211
if (path.empty() || path == "/") {
211212
*root = item;
212213
return true;

0 commit comments

Comments
 (0)