@@ -14,6 +14,48 @@ import (
1414 "github.com/NVIDIA/aistore/cmn/debug"
1515)
1616
17+ // Static descriptor table (xact.Table) - one entry per xaction kind.
18+ // The table drives runtime decisions that would otherwise be scattered across the codebase:
19+ // what can be started, what aborts what, and which xactions can coexist.
20+ //
21+ // The table (below) is static, public, and global Kind => [] map that contains
22+ // xaction kinds and static properties, such as `Startable`, `Owned`, etc.
23+ //
24+ // In particular, "startability" is defined as ability to start xaction via `api.StartXaction`
25+ // (whereby copying bucket, for instance, requires a separate `api.CopyBucket`, etc.)
26+ //
27+ // Coexistence with rebalance and resilver
28+ // ---------------------------------------
29+ // Two flags govern the relationship between a given xaction kind and a cluster-wide
30+ // rebalance (or node-local resilver) run:
31+ //
32+ // ConflictRebRes - refuse to start this kind when rebalance/resilver is already in progress;
33+ // conversely, refuse to start rebalance/resilver when this kind is running.
34+ // Enforced at xreg renew time.
35+ //
36+ // AbortByReb - abort in-flight instances of this kind when a new rebalance starts.
37+ // Enforced by xreg.AbortByNewReb() at the top of reb.Run().
38+ //
39+ // In practice the two almost always travel together: if the target set must be stable to
40+ // start the xaction, it must remain stable to finish it. The exceptions are deliberate:
41+ //
42+ // AbortByReb without ConflictRebRes - ETLInline, BlobDl, Download.
43+ // These are long-running or on-demand and shouldn't be refused at start time just
44+ // because rebalance happens to be running, but they cannot correctly survive a
45+ // topology change mid-flight.
46+ //
47+ // ConflictRebRes without AbortByReb - IndexShard.
48+ // Builds a best-effort index; stale entries are detected via LOM checksum and fall
49+ // back to tar.Next() scan. Aborting a 90%-complete build is wasteful when the partial
50+ // output remains useful and a resumed build atomically skips already-indexed LOMs
51+ // (lom.md.flags&Indexed + index file as an atomic pair).
52+ //
53+ // Rebalance and Resilver flags
54+ // ----------------------------
55+ // Rebalance=true and Resilver=true mark the xactions that ARE the rebalance/resilver
56+ // themselves (plus ActMoveBck which performs a rebalance-like move). They are informational
57+ // and used by xreg to recognize self-conflicts.
58+
1759const (
1860 ScopeG = iota + 1 // cluster
1961 ScopeB // bucket
3375 // see xreg for "limited coexistence"
3476 Rebalance bool // moves data between nodes
3577 Resilver bool // moves data between mountpaths
36- ConflictRebRes bool // conflicts with rebalance/ resilver
37- AbortRebRes bool // gets aborted upon rebalance/resilver - currently, all `ext`-ensions
78+ ConflictRebRes bool // starting this job would conflict with rebalance or resilver that's currently in progress
79+ AbortByReb bool // gets aborted upon rebalance (coincides with ConflictRebRes with very few exceptions)
3880
3981 // xaction has an intermediate `idle` state whereby it "idles" between requests
4082 // (see related: xact/demand.go)
@@ -54,17 +96,12 @@ type (
5496// Descriptor //
5597////////////////
5698
57- // `xact.Table` is a static, public, and global Kind=>[Xaction Descriptor] map that contains
58- // xaction kinds and static properties, such as `Startable`, `Owned`, etc.
59- // In particular, "startability" is narrowly defined as ability to start xaction
60- // via `api.StartXaction`
61- // (whereby copying bucket, for instance, requires a separate `api.CopyBucket`, etc.)
6299var Table = map [string ]Descriptor {
63100 // bucket-less xactions that will typically have a 'cluster' scope (with resilver being a notable exception)
64101 apc .ActElection : {DisplayName : "elect-primary" , Scope : ScopeG , Startable : false },
65102 apc .ActRebalance : {Scope : ScopeG , Startable : true , Metasync : true , Rebalance : true },
66103
67- apc .ActETLInline : {Scope : ScopeG , Startable : false , AbortRebRes : true },
104+ apc .ActETLInline : {Scope : ScopeG , Startable : false , AbortByReb : true },
68105
69106 // (one bucket) | (all buckets)
70107 apc .ActLRU : {DisplayName : "lru-eviction" , Scope : ScopeGB , Startable : true },
@@ -79,8 +116,8 @@ var Table = map[string]Descriptor{
79116
80117 // single target (node)
81118 apc .ActResilver : {Scope : ScopeT , Startable : true , Resilver : true },
82- apc .ActRechunk : {Scope : ScopeB , Startable : true , RefreshCap : true , ConflictRebRes : true },
83- apc .ActIndexShard : {Scope : ScopeB , Startable : true , RefreshCap : false , ConflictRebRes : true },
119+ apc .ActRechunk : {Scope : ScopeB , Startable : true , RefreshCap : true , ConflictRebRes : true , AbortByReb : true },
120+ apc .ActIndexShard : {Scope : ScopeB , Startable : true , RefreshCap : false , ConflictRebRes : true , AbortByReb : false },
84121
85122 // on-demand EC and n-way replication
86123 // (non-startable, triggered by PUT => erasure-coded or mirrored bucket)
@@ -90,30 +127,33 @@ var Table = map[string]Descriptor{
90127 apc .ActPutCopies : {Scope : ScopeB , Startable : false , RefreshCap : true , Idles : true },
91128
92129 //
93- // on-demand multi-object (consider setting ConflictRebRes = true)
130+ // on-demand multi-object
94131 //
95132 apc .ActArchive : {Scope : ScopeB , Access : apc .AccessRW , Startable : false , RefreshCap : true , Idles : true },
96133 apc .ActCopyObjects : {
97- DisplayName : "copy-objects" ,
98- Scope : ScopeB ,
99- Access : apc .AccessRW , // apc.AceCreateBucket is checked as well but only if ais://dst doesn't exist
100- Startable : false ,
101- RefreshCap : true ,
102- Idles : true ,
134+ DisplayName : "copy-objects" ,
135+ Scope : ScopeB ,
136+ Access : apc .AccessRW , // apc.AceCreateBucket is checked as well but only if ais://dst doesn't exist
137+ Startable : false ,
138+ RefreshCap : true ,
139+ Idles : true ,
140+ ConflictRebRes : true ,
141+ AbortByReb : true ,
103142 },
104143 apc .ActETLObjects : {
105- DisplayName : "etl-objects" ,
106- Scope : ScopeB ,
107- Access : apc .AccessRW , // ditto
108- Startable : false ,
109- RefreshCap : true ,
110- Idles : true ,
111- AbortRebRes : true ,
144+ DisplayName : "etl-objects" ,
145+ Scope : ScopeB ,
146+ Access : apc .AccessRW , // ditto
147+ Startable : false ,
148+ RefreshCap : true ,
149+ Idles : true ,
150+ ConflictRebRes : true ,
151+ AbortByReb : true ,
112152 },
113153
114- apc .ActBlobDl : {Access : apc .AccessRW , Scope : ScopeB , Startable : true , AbortRebRes : true , RefreshCap : true },
154+ apc .ActBlobDl : {Access : apc .AccessRW , Scope : ScopeB , Startable : true , AbortByReb : true , RefreshCap : true },
115155
116- apc .ActDownload : {Access : apc .AccessRW , Scope : ScopeG , Startable : false , Idles : true , AbortRebRes : true },
156+ apc .ActDownload : {Access : apc .AccessRW , Scope : ScopeG , Startable : false , Idles : true , AbortByReb : true },
117157
118158 // in its own class
119159 apc .ActDsort : {
@@ -122,9 +162,9 @@ var Table = map[string]Descriptor{
122162 Access : apc .AccessRW ,
123163 Startable : false ,
124164 RefreshCap : true ,
125- ConflictRebRes : true ,
126165 ExtendedStats : true ,
127- AbortRebRes : true ,
166+ ConflictRebRes : true ,
167+ AbortByReb : true ,
128168 },
129169
130170 // multi-object
@@ -173,6 +213,7 @@ var Table = map[string]Descriptor{
173213 Metasync : true ,
174214 RefreshCap : true ,
175215 ConflictRebRes : true ,
216+ AbortByReb : true ,
176217 },
177218 apc .ActMakeNCopies : {
178219 DisplayName : "mirror" ,
@@ -190,6 +231,7 @@ var Table = map[string]Descriptor{
190231 Metasync : true ,
191232 Rebalance : true ,
192233 ConflictRebRes : true ,
234+ AbortByReb : true ,
193235 },
194236 apc .ActCopyBck : {
195237 DisplayName : "copy-bucket" ,
@@ -199,22 +241,24 @@ var Table = map[string]Descriptor{
199241 Metasync : true ,
200242 RefreshCap : true ,
201243 ConflictRebRes : true ,
244+ AbortByReb : true ,
202245 },
203246 apc .ActETLBck : {
204- DisplayName : "etl-bucket" ,
205- Scope : ScopeB ,
206- Access : apc .AccessRW , // ditto
207- Startable : false , // ditto
208- Metasync : true ,
209- RefreshCap : true ,
210- AbortRebRes : true ,
247+ DisplayName : "etl-bucket" ,
248+ Scope : ScopeB ,
249+ Access : apc .AccessRW , // ditto
250+ Startable : false , // ditto
251+ Metasync : true ,
252+ RefreshCap : true ,
253+ ConflictRebRes : true ,
254+ AbortByReb : true ,
211255 },
212256
213257 apc .ActList : {Scope : ScopeB , Access : apc .AceObjLIST , Startable : false , Metasync : false , Idles : true , QuietBrief : true },
214258
215- apc .ActGetBatch : {Scope : ScopeGB , Startable : false , Metasync : false , ConflictRebRes : true , Idles : true , QuietBrief : true }, // x-moss
259+ apc .ActGetBatch : {Scope : ScopeGB , Startable : false , Metasync : false , ConflictRebRes : true , AbortByReb : true , Idles : true , QuietBrief : true }, // x-moss
216260
217- apc .ActCreateNBI : {Scope : ScopeB , Startable : false , Metasync : false , ConflictRebRes : true , Idles : false },
261+ apc .ActCreateNBI : {Scope : ScopeB , Startable : false , Metasync : false , ConflictRebRes : true , AbortByReb : true , Idles : false },
218262
219263 // cache management, internal usage
220264 apc .ActLoadLomCache : {DisplayName : "warm-up-metadata" , Scope : ScopeB , Startable : true },
0 commit comments