@@ -380,8 +380,9 @@ type dirMeta struct {
380380
381381func newDirMeta () * dirMeta { return & dirMeta {usage : & QuotaUsage {}} }
382382
383- func (* dirMeta ) trieMeta () {}
384- func (dm * dirMeta ) update (quota * Quota ) { dm .quota .Store (quota ) }
383+ func (* dirMeta ) trieMeta () {}
384+ func (dm * dirMeta ) setQuota (quota * Quota ) { dm .quota .Store (quota ) }
385+ func (dm * dirMeta ) getQuota () * Quota { return dm .quota .Load ().(* Quota ) }
385386
386387func (dm * dirMeta ) withinQuota (metrics , namespaces , logical , physical , dataPoints int64 ) bool {
387388 quota , ok := dm .quota .Load ().(* Quota )
@@ -538,6 +539,8 @@ func (ti *trieIndex) insert(path string, logicalSize, physicalSize, dataPoints,
538539 var start , nlen int
539540 var sn , newn * trieNode
540541 var cur = ti .root
542+ var dirNodes = [16 ]* trieNode {ti .root } // why arrray: avoiding heap allocation
543+ var dirNodesIdx = 1
541544outer:
542545 // why len(path)+1: make sure the last node is also processed in the loop
543546 for i := 0 ; i < len (path )+ 1 ; i ++ {
@@ -649,12 +652,36 @@ outer:
649652 if child .dir () {
650653 cur = child
651654 cur .gen = ti .root .gen
655+
656+ if dirNodesIdx < len (dirNodes ) {
657+ dirNodes [dirNodesIdx ] = child
658+ dirNodesIdx ++
659+ }
652660 continue outer
653661 }
654662 }
655663
656664 if i < len (path ) {
657665 newn = ti .newDir ()
666+
667+ if dirNodesIdx < len (dirNodes ) {
668+ if dirNodes [dirNodesIdx - 1 ].meta != nil {
669+ // Purpose of transient child?
670+ //
671+ //
672+ pmeta := dirNodes [dirNodesIdx - 1 ].meta
673+ pquota , ok := pmeta .(* dirMeta ).quota .Load ().(* Quota )
674+ if ok && pquota .TransientChild != nil {
675+ meta := newDirMeta ()
676+ meta .setQuota (pquota .TransientChild )
677+ newn .meta = meta
678+ }
679+ }
680+
681+ dirNodes [dirNodesIdx ] = newn
682+ dirNodesIdx ++
683+ }
684+
658685 cur .addChild (newn )
659686 cur = newn
660687 }
@@ -720,7 +747,24 @@ outer:
720747 cur .addChild (child )
721748 cur = child
722749
750+ // TODO: need to support realtime and concurrent index?
723751 ti .fileCount ++
752+
753+ for i := 0 ; i < dirNodesIdx ; i ++ {
754+ if dirNodes [i ] == nil {
755+ continue
756+ }
757+
758+ meta , ok := dirNodes [i ].meta .(* dirMeta )
759+ if ! ok || meta .usage == nil {
760+ continue
761+ }
762+
763+ atomic .AddInt64 (& meta .usage .Metrics , 1 )
764+ atomic .AddInt64 (& meta .usage .LogicalSize , logicalSize )
765+ atomic .AddInt64 (& meta .usage .PhysicalSize , physicalSize )
766+ atomic .AddInt64 (& meta .usage .DataPoints , dataPoints )
767+ }
724768 }
725769
726770 return cur , nil
@@ -1570,8 +1614,14 @@ type Quota struct {
15701614
15711615 DroppingPolicy QuotaDroppingPolicy
15721616 StatMetricPrefix string
1617+
1618+ // See details in trieIndex.insert
1619+ TransientChild * Quota
1620+ IsTransient bool // for avoid emitting metrics for transient quota nodes.
15731621}
15741622
1623+ // var transientQuota = &Quota{Metrics: 10000, Throughput: 10000, DroppingPolicy: QDPNew, StatMetricPrefix: "transient"}
1624+
15751625func (q * Quota ) String () string {
15761626 return fmt .Sprintf ("pattern:%s,dirs:%d,files:%d,points:%d,logical:%d,physical:%d,throughput:%d,policy:%s" , q .Pattern , q .Namespaces , q .Metrics , q .DataPoints , q .LogicalSize , q .PhysicalSize , q .Throughput , q .DroppingPolicy )
15771627}
@@ -1788,7 +1838,7 @@ func (ti *trieIndex) applyQuotas(resetFrequency time.Duration, quotas ...*Quota)
17881838 if quota .Pattern == "/" {
17891839 if ! updateChecker ["/" ] {
17901840 meta := ti .root .meta .(* dirMeta )
1791- meta .update (quota )
1841+ meta .setQuota (quota )
17921842 ti .throughputs .store ("/" , newThroughputUsagePerNamespace (ti .root .gen , quota , meta .usage ))
17931843
17941844 updateChecker ["/" ] = true
@@ -1804,6 +1854,7 @@ func (ti *trieIndex) applyQuotas(resetFrequency time.Duration, quotas ...*Quota)
18041854
18051855 for i , node := range nodes {
18061856 if node .meta == nil {
1857+ // TODO: has data race in throttle, generateQuotaAndUsageMetrics and other places?
18071858 node .meta = newDirMeta ()
18081859 }
18091860
@@ -1819,7 +1870,7 @@ func (ti *trieIndex) applyQuotas(resetFrequency time.Duration, quotas ...*Quota)
18191870
18201871 if ! updateChecker [paths [i ]] {
18211872 ti .throughputs .store (paths [i ], newThroughputUsagePerNamespace (ti .root .gen , quota , meta .usage ))
1822- meta .update (quota )
1873+ meta .setQuota (quota )
18231874
18241875 updateChecker [paths [i ]] = true
18251876 }
@@ -1838,7 +1889,7 @@ func (ti *trieIndex) applyQuotas(resetFrequency time.Duration, quotas ...*Quota)
18381889}
18391890
18401891// refreshUsage updates usage data and generate stat metrics.
1841- // It can't be evoked with concurrent trieIndex.insert.
1892+ // It can't be evoked with concurrently trieIndex.insert.
18421893func (ti * trieIndex ) refreshUsage (throughputs * throughputQuotaManager ) (files uint64 ) {
18431894 if throughputs == nil {
18441895 throughputs = newQuotaThroughputQuotaManager ()
@@ -1895,8 +1946,10 @@ func (ti *trieIndex) refreshUsage(throughputs *throughputQuotaManager) (files ui
18951946 tname = name
18961947 }
18971948 var prefix string
1949+ var isTransient bool
18981950 if quota , ok := cur .node .meta .(* dirMeta ).quota .Load ().(* Quota ); ok {
18991951 prefix = quota .StatMetricPrefix
1952+ isTransient = quota .IsTransient
19001953 }
19011954
19021955 var throughput int64
@@ -1906,7 +1959,9 @@ func (ti *trieIndex) refreshUsage(throughputs *throughputQuotaManager) (files ui
19061959
19071960 throttled := atomic .LoadInt64 (& usage .Throttled )
19081961
1909- ti .generateQuotaAndUsageMetrics (prefix , strings .ReplaceAll (name , "." , "-" ), cur .node , throughput , throttled )
1962+ if ! isTransient {
1963+ ti .generateQuotaAndUsageMetrics (prefix , strings .ReplaceAll (name , "." , "-" ), cur .node , throughput , throttled )
1964+ }
19101965
19111966 if throttled > 0 {
19121967 atomic .AddInt64 (& usage .Throttled , - throttled )
0 commit comments