wilfred-s commented on code in PR #563:
URL: https://github.com/apache/yunikorn-core/pull/563#discussion_r1237969497
##########
pkg/scheduler/objects/application.go:
##########
@@ -1631,24 +1631,22 @@ func (sa *Application) addAllocationInternal(info
*Allocation) {
// Increase user resource usage
// No locking must be called while holding the lock
func (sa *Application) incUserResourceUsage(resource *resources.Resource) {
- if err := ugm.GetUserManager().IncreaseTrackedResource(sa.queuePath,
sa.ApplicationID, resource, sa.user); err != nil {
- log.Log(log.SchedApplication).Error("Unable to track the user
resource usage",
+ if allowed :=
ugm.GetUserManager().IncreaseTrackedResource(sa.queuePath, sa.ApplicationID,
resource, sa.user); !allowed {
+ log.Log(log.SchedUGM).Error("Not allowed to increase the user
resource usage",
Review Comment:
Not an error, debug at best.
Also need to be careful that we do not log the same information in multiple
places. This same thing is logged in ugm as a WARN. Preferably log in ugm and
not the application.
##########
pkg/scheduler/ugm/manager.go:
##########
@@ -33,25 +33,24 @@ import (
var once sync.Once
var m *Manager
-const maxresources = "maxresources"
-const maxapplications = "maxapplications"
+const wildcard = "*"
Review Comment:
This should already be defined somewhere I would assume, if not it has to be
moved to common constants.
##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,102 +29,197 @@ import (
type QueueTracker struct {
queueName string
+ parent *QueueTracker
+ queuePath string
resourceUsage *resources.Resource
runningApplications map[string]bool
- maxResourceUsage *resources.Resource
+ maxResources *resources.Resource
maxRunningApps uint64
childQueueTrackers map[string]*QueueTracker
}
func newRootQueueTracker() *QueueTracker {
- return newQueueTracker(configs.RootQueue)
+ qt := newQueueTracker(configs.RootQueue, nil)
+ return qt
}
-func newQueueTracker(queueName string) *QueueTracker {
- log.Log(log.SchedUGM).Debug("Creating queue tracker object for queue",
- zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
queueTracker := &QueueTracker{
queueName: queueName,
+ parent: parent,
resourceUsage: resources.NewResource(),
runningApplications: make(map[string]bool),
+ maxResources: resources.NewResource(),
+ maxRunningApps: 0,
childQueueTrackers: make(map[string]*QueueTracker),
}
+ parentQueueName := ""
+ if parent != nil {
+ queueTracker.queuePath = queueTracker.parent.queuePath +
configs.DOT + queueName
+ parentQueueName = parent.queueName
+ } else if queueName == configs.RootQueue {
+ queueTracker.queuePath = configs.RootQueue
+ }
+ log.Log(log.SchedUGM).Debug("Created queue tracker object for queue",
+ zap.String("queue", queueName),
+ zap.String("parent", parentQueueName),
+ zap.String("queue path ", queueTracker.queuePath))
return queueTracker
}
-func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+ none trackingType = iota
+ user
+ group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, trackType trackingType, usage *resources.Resource) bool {
log.Log(log.SchedUGM).Debug("Increasing resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage))
- if queuePath == "" || applicationID == "" || usage == nil {
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
+ finalResourceUsage := qt.resourceUsage.Clone()
+ finalResourceUsage.AddTo(usage)
+ wildCardQuotaExceeded := false
+ existingApp := qt.runningApplications[applicationID]
+
+ // apply user/group specific limit settings set if configured,
otherwise use wild card limit settings
+ if qt.maxRunningApps != 0 && !resources.Equals(resources.NewResource(),
qt.maxResources) {
+ log.Log(log.SchedUGM).Debug("applying enforcement checks using
limit settings of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("max running apps", qt.maxRunningApps),
+ zap.String("max resources", qt.maxResources.String()))
+ if (!existingApp && len(qt.runningApplications)+1 >
int(qt.maxRunningApps)) ||
+ resources.StrictlyGreaterThan(finalResourceUsage,
qt.maxResources) {
+ log.Log(log.SchedUGM).Warn("Unable to increase resource
usage as allowing new application to run would exceed either configured max
applications or max resources limit of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
qt.maxRunningApps),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
qt.maxResources.String()))
+ return false
+ }
}
+
+ // Try wild card settings
+ if qt.maxRunningApps == 0 && resources.Equals(resources.NewResource(),
qt.maxResources) {
+ // Is there any wild card settings? Do we need to apply
enforcement checks using wild card limit settings?
+ var config *LimitConfig
+ if trackType == user {
+ config = m.getUserWildCardLimitsConfig(qt.queuePath)
+ } else if trackType == group {
+ config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+ }
+ if config != nil {
+ log.Log(log.SchedUGM).Debug("applying enforcement
checks using limit settings of wild card user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("wild card max running apps",
config.maxApplications),
+ zap.String("wild card max resources",
config.maxResources.String()),
+ zap.Bool("wild card quota exceeded",
wildCardQuotaExceeded))
+ wildCardQuotaExceeded = (config.maxApplications != 0 &&
!existingApp && len(qt.runningApplications)+1 > int(config.maxApplications)) ||
+ (!resources.Equals(resources.NewResource(),
config.maxResources) && resources.StrictlyGreaterThan(finalResourceUsage,
config.maxResources))
+ if wildCardQuotaExceeded {
+ log.Log(log.SchedUGM).Warn("Unable to increase
resource usage as allowing new application to run would exceed either
configured max applications or max resources limit of wild card user/group",
+ zap.Int("tracking type",
int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
config.maxApplications),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
config.maxResources.String()))
+ return false
+ }
+ }
+ }
+
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if childQueuePath != "" {
+ if qt.childQueueTrackers[immediateChildQueueName] == nil {
+ qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(immediateChildQueueName, qt)
+ }
+ allowed :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, trackType, usage)
+ if !allowed {
+ return allowed
+ }
+ }
+
qt.resourceUsage.AddTo(usage)
qt.runningApplications[applicationID] = true
log.Log(log.SchedUGM).Debug("Successfully increased resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
+ zap.Bool("existing app", existingApp),
zap.Stringer("resource", usage),
zap.Stringer("total resource after increasing",
qt.resourceUsage),
zap.Int("total applications after increasing",
len(qt.runningApplications)))
-
- childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
- if childQueuePath != "" {
- if qt.childQueueTrackers[immediateChildQueueName] == nil {
- qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(immediateChildQueueName)
- }
- err :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, usage)
- if err != nil {
- return err
- }
- }
- return nil
+ return true
}
-func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, error) {
+func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, bool) {
log.Log(log.SchedUGM).Debug("Decreasing resource usage",
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
- if queuePath == "" || usage == nil {
- return false, fmt.Errorf("mandatory parameters are missing.
queuepath: %s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
- }
- qt.resourceUsage.SubFrom(usage)
- if removeApp {
- delete(qt.runningApplications, applicationID)
- }
- log.Log(log.SchedUGM).Debug("Successfully decreased resource usage",
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.Stringer("total resource after decreasing",
qt.resourceUsage),
- zap.Int("total applications after decreasing",
len(qt.runningApplications)))
-
childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
if childQueuePath != "" {
if qt.childQueueTrackers[immediateChildQueueName] != nil {
- removeQT, err :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
- if err != nil {
- return false, err
+ removeQT, decreased :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
+ if !decreased {
+ return false, decreased
}
if removeQT {
+ log.Log(log.SchedUGM).Debug("Removed queue
tracker linkage from its parent",
+ zap.String("queue path ", queuePath),
+ zap.String("removed queue name",
immediateChildQueueName),
+ zap.String("parent queue",
qt.queueName))
delete(qt.childQueueTrackers,
immediateChildQueueName)
}
} else {
log.Log(log.SchedUGM).Error("Child queueTracker tracker
must be available in child queues map",
zap.String("child queueTracker name",
immediateChildQueueName))
- return false, fmt.Errorf("child queueTracker tracker
for %s is missing in child queues map", immediateChildQueueName)
+ return false, false
}
}
+ qt.resourceUsage.SubFrom(usage)
+ if removeApp {
+ log.Log(log.SchedUGM).Debug("Removed application from running
applications",
+ zap.String("application", applicationID),
+ zap.String("queue path", queuePath),
+ zap.String("queue name", qt.queueName))
+ delete(qt.runningApplications, applicationID)
+ }
+ log.Log(log.SchedUGM).Debug("Successfully decreased resource usage",
+ zap.String("queue path", queuePath),
+ zap.String("application", applicationID),
+ zap.Stringer("resource", usage),
+ zap.Stringer("total resource after decreasing",
qt.resourceUsage),
+ zap.Int("total applications after decreasing",
len(qt.runningApplications)))
+
// Determine if the queue tracker should be removed
- removeQT := len(qt.childQueueTrackers) == 0 &&
len(qt.runningApplications) == 0 && resources.IsZero(qt.resourceUsage)
- return removeQT, nil
+ removeQT := len(qt.childQueueTrackers) == 0 &&
len(qt.runningApplications) == 0 && resources.IsZero(qt.resourceUsage) &&
+ qt.maxRunningApps == 0 &&
resources.Equals(resources.NewResource(), qt.maxResources)
+ log.Log(log.SchedUGM).Debug("Can queue tracker be removed?",
+ zap.String("queue path ", queuePath),
+ zap.Int("no. of child queue trackers",
len(qt.childQueueTrackers)),
+ zap.Int("no. of running applications",
len(qt.runningApplications)),
+ zap.Bool("current resource usage",
resources.IsZero(qt.resourceUsage)),
+ zap.Uint64("max running applications", qt.maxRunningApps),
+ zap.String("max resources", qt.maxResources.String()),
+ zap.Bool("remove QT", removeQT))
Review Comment:
Lot of overhead: we know exactly when we need to remove,
Create a single DEBUG log line:
```
log.Log(log.SchedUGM).Debug("Remove queue tracker",
zap.String("queue path ", queuePath),
zap.Bool("remove ", removeQT))
```
##########
pkg/scheduler/ugm/manager.go:
##########
@@ -195,60 +159,79 @@ func (m *Manager) DecreaseTrackedResource(queuePath
string, applicationID string
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s, user: %s",
- queuePath, applicationID, usage.String(), user.User)
+ return false
}
m.Lock()
defer m.Unlock()
userTracker := m.userTrackers[user.User]
if userTracker != nil {
- removeQT, err := userTracker.decreaseTrackedResource(queuePath,
applicationID, usage, removeApp)
- if err != nil {
- log.Log(log.SchedUGM).Error("Problem in decreasing the
user resource usage",
+ log.Log(log.SchedUGM).Debug("Decreasing resource usage for
user",
Review Comment:
turn if around
##########
pkg/scheduler/partition_test.go:
##########
@@ -346,7 +346,7 @@ func TestRemoveNodeWithAllocations(t *testing.T) {
assert.Equal(t, 1, len(released), "node did not release correct
allocation")
assert.Equal(t, 0, len(confirmed), "node did not confirm correct
allocation")
assert.Equal(t, released[0].GetUUID(), allocUUID, "uuid returned by
release not the same as on allocation")
- assertLimits(t, getTestUserGroup(), nil)
+ assertLimits(t, getTestUserGroup(), resources.Multiply(appRes, 0))
Review Comment:
Why is this not a `resource.Zero` ?
##########
pkg/scheduler/ugm/manager.go:
##########
@@ -419,30 +348,40 @@ func (m *Manager) UpdateConfig(config
configs.QueueConfig, queuePath string) err
m.Lock()
defer m.Unlock()
- // clear the local limit config maps before processing the limit config
- m.userLimitsConfig = make(map[string]map[string]map[string]interface{})
- m.groupLimitsConfig = make(map[string]map[string]map[string]interface{})
+ m.userWildCardLimitsConfig = make(map[string]*LimitConfig)
+ m.groupWildCardLimitsConfig = make(map[string]*LimitConfig)
return m.internalProcessConfig(config, queuePath)
}
func (m *Manager) internalProcessConfig(cur configs.QueueConfig, queuePath
string) error {
// Holds user and group for which limits have been configured with
specific queue path
- userGroupLimits := make(map[string]bool)
+ userLimits := make(map[string]bool)
+ groupLimits := make(map[string]bool)
// Traverse limits of specific queue path
for _, limit := range cur.Limits {
- tempLimitsMap := make(map[string]interface{})
- tempLimitsMap[maxresources] = limit.MaxResources
- tempLimitsMap[maxapplications] = limit.MaxApplications
+ var maxResource *resources.Resource
+ var err error
+ if maxResource, err =
resources.NewResourceFromConf(limit.MaxResources); err != nil {
+ log.Log(log.SchedUGM).Debug("Problem in using the wild
card limit max resources settings.",
Review Comment:
Assume all resources can be parsed: the config must have passed the
validation before we get here
##########
pkg/scheduler/ugm/manager.go:
##########
@@ -475,113 +416,119 @@ func (m *Manager) internalProcessConfig(cur
configs.QueueConfig, queuePath strin
return nil
}
-func (m *Manager) processUserConfig(user string, limit configs.Limit,
queuePath string, userGroupLimits map[string]bool, tempLimitsMap
map[string]interface{}, tempUserMap map[string]map[string]interface{}) error {
+func (m *Manager) processUserConfig(user string, limit configs.Limit,
queuePath string, userLimits map[string]bool) error {
if user == "*" {
// traverse all tracked users
for u, ut := range m.userTrackers {
// Is this user already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(ut.queueTracker,
queuePath) {
+ if ut.IsQueuePathTrackedCompletely(queuePath) {
log.Log(log.SchedUGM).Debug("Processing wild
card user limits configuration for all existing users",
zap.String("user", u),
zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
zap.Uint64("max application",
limit.MaxApplications),
zap.Any("max resources",
limit.MaxResources))
-
- // creates an entry for the user being
processed always as it has been cleaned before
- if _, ok := m.userLimitsConfig[u]; ok {
- m.userLimitsConfig[u][queuePath] =
tempLimitsMap
- } else {
- m.userLimitsConfig[u] = tempUserMap
- }
if err := m.setUserLimits(u, limit, queuePath);
err != nil {
return err
}
- userGroupLimits[u] = true
+ userLimits[u] = true
}
}
- } else {
- // creates an entry for the user being processed always as it
has been cleaned before
- if _, ok := m.userLimitsConfig[user]; ok {
- m.userLimitsConfig[user][queuePath] = tempLimitsMap
- } else {
- m.userLimitsConfig[user] = tempUserMap
- }
+ } else if user != "" {
if err := m.setUserLimits(user, limit, queuePath); err != nil {
return err
}
- userGroupLimits[user] = true
+ userLimits[user] = true
}
return nil
}
-func (m *Manager) processGroupConfig(group string, limit configs.Limit,
queuePath string, userGroupLimits map[string]bool, tempLimitsMap
map[string]interface{}, tempGroupMap map[string]map[string]interface{}) error {
+func (m *Manager) processGroupConfig(group string, limit configs.Limit,
queuePath string, groupLimits map[string]bool) error {
if group == "*" {
// traverse all tracked groups
for g, gt := range m.groupTrackers {
// Is this group already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(gt.queueTracker,
queuePath) {
+ if gt.IsQueuePathTrackedCompletely(queuePath) {
log.Log(log.SchedUGM).Debug("Processing wild
card user limits configuration for all existing groups",
zap.String("group", g),
zap.String("limit", limit.Limit),
zap.String("queue path", queuePath),
zap.Uint64("max application",
limit.MaxApplications),
zap.Any("max resources",
limit.MaxResources))
- // creates an entry for the group being
processed always as it has been cleaned before
- if _, ok := m.groupLimitsConfig[g]; ok {
- m.groupLimitsConfig[g][queuePath] =
tempLimitsMap
- } else {
- m.groupLimitsConfig[g] = tempGroupMap
- }
if err := m.setGroupLimits(g, limit,
queuePath); err != nil {
return err
}
- userGroupLimits[g] = true
+ groupLimits[g] = true
}
}
- } else {
- // creates an entry for the group being processed always as it
has been cleaned before
- if _, ok := m.groupLimitsConfig[group]; ok {
- m.groupLimitsConfig[group][queuePath] = tempLimitsMap
- } else {
- m.groupLimitsConfig[group] = tempGroupMap
- }
+ } else if group != "" {
if err := m.setGroupLimits(group, limit, queuePath); err != nil
{
return err
}
- userGroupLimits[group] = true
+ groupLimits[group] = true
}
return nil
}
-func (m *Manager) clearEarlierSetLimits(userGroupLimits map[string]bool,
queuePath string) error {
- // Clear already configured limits of user for which limits have been
configured before but not now through #cur
+// clearEarlierSetLimits Clear already configured limits of users and groups
for which limits have been configured before but not now
+func (m *Manager) clearEarlierSetLimits(userLimits map[string]bool,
groupLimits map[string]bool, queuePath string) error {
+ // Clear already configured limits of user for which limits have been
configured before but not now
for u, ut := range m.userTrackers {
// Is this user already tracked for the queue path?
- if m.IsQueuePathTrackedCompletely(ut.queueTracker, queuePath) {
- if _, ok := userGroupLimits[u]; !ok {
- err :=
ut.setMaxResources(resources.NewResource(), queuePath)
- if err != nil {
- return err
+ if ut.IsQueuePathTrackedCompletely(queuePath) {
+ // Is there any limit config set for user in the
current configuration? If not, then clear those old limit settings
+ if _, ok := userLimits[u]; !ok {
+ log.Log(log.SchedUGM).Debug("Need to clear
earlier set configs for user",
+ zap.String("user", u),
+ zap.String("queue path", queuePath))
+ // Is there any running applications in end
queue of this queue path? If not, then remove the linkage between end queue and
its immediate parent
+ if ut.IsUnlinkRequired(queuePath) {
+ ut.UnlinkQT(queuePath)
+ } else {
+
ut.setMaxResources(resources.NewResource(), queuePath)
+ ut.setMaxApplications(0, queuePath)
Review Comment:
Use one function to set both, propagate that into all objects
##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -31,102 +29,197 @@ import (
type QueueTracker struct {
queueName string
+ parent *QueueTracker
+ queuePath string
resourceUsage *resources.Resource
runningApplications map[string]bool
- maxResourceUsage *resources.Resource
+ maxResources *resources.Resource
maxRunningApps uint64
childQueueTrackers map[string]*QueueTracker
}
func newRootQueueTracker() *QueueTracker {
- return newQueueTracker(configs.RootQueue)
+ qt := newQueueTracker(configs.RootQueue, nil)
+ return qt
}
-func newQueueTracker(queueName string) *QueueTracker {
- log.Log(log.SchedUGM).Debug("Creating queue tracker object for queue",
- zap.String("queue", queueName))
+func newQueueTracker(queueName string, parent *QueueTracker) *QueueTracker {
queueTracker := &QueueTracker{
queueName: queueName,
+ parent: parent,
resourceUsage: resources.NewResource(),
runningApplications: make(map[string]bool),
+ maxResources: resources.NewResource(),
+ maxRunningApps: 0,
childQueueTrackers: make(map[string]*QueueTracker),
}
+ parentQueueName := ""
+ if parent != nil {
+ queueTracker.queuePath = queueTracker.parent.queuePath +
configs.DOT + queueName
+ parentQueueName = parent.queueName
+ } else if queueName == configs.RootQueue {
+ queueTracker.queuePath = configs.RootQueue
+ }
+ log.Log(log.SchedUGM).Debug("Created queue tracker object for queue",
+ zap.String("queue", queueName),
+ zap.String("parent", parentQueueName),
+ zap.String("queue path ", queueTracker.queuePath))
return queueTracker
}
-func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource) error {
+type trackingType int
+
+const (
+ none trackingType = iota
+ user
+ group
+)
+
+func (qt *QueueTracker) increaseTrackedResource(queuePath string,
applicationID string, trackType trackingType, usage *resources.Resource) bool {
log.Log(log.SchedUGM).Debug("Increasing resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage))
- if queuePath == "" || applicationID == "" || usage == nil {
- return fmt.Errorf("mandatory parameters are missing. queuepath:
%s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
+ finalResourceUsage := qt.resourceUsage.Clone()
+ finalResourceUsage.AddTo(usage)
+ wildCardQuotaExceeded := false
+ existingApp := qt.runningApplications[applicationID]
+
+ // apply user/group specific limit settings set if configured,
otherwise use wild card limit settings
+ if qt.maxRunningApps != 0 && !resources.Equals(resources.NewResource(),
qt.maxResources) {
+ log.Log(log.SchedUGM).Debug("applying enforcement checks using
limit settings of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("max running apps", qt.maxRunningApps),
+ zap.String("max resources", qt.maxResources.String()))
+ if (!existingApp && len(qt.runningApplications)+1 >
int(qt.maxRunningApps)) ||
+ resources.StrictlyGreaterThan(finalResourceUsage,
qt.maxResources) {
+ log.Log(log.SchedUGM).Warn("Unable to increase resource
usage as allowing new application to run would exceed either configured max
applications or max resources limit of specific user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
qt.maxRunningApps),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
qt.maxResources.String()))
+ return false
+ }
}
+
+ // Try wild card settings
+ if qt.maxRunningApps == 0 && resources.Equals(resources.NewResource(),
qt.maxResources) {
+ // Is there any wild card settings? Do we need to apply
enforcement checks using wild card limit settings?
+ var config *LimitConfig
+ if trackType == user {
+ config = m.getUserWildCardLimitsConfig(qt.queuePath)
+ } else if trackType == group {
+ config = m.getGroupWildCardLimitsConfig(qt.queuePath)
+ }
+ if config != nil {
+ log.Log(log.SchedUGM).Debug("applying enforcement
checks using limit settings of wild card user/group",
+ zap.Int("tracking type", int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Uint64("wild card max running apps",
config.maxApplications),
+ zap.String("wild card max resources",
config.maxResources.String()),
+ zap.Bool("wild card quota exceeded",
wildCardQuotaExceeded))
+ wildCardQuotaExceeded = (config.maxApplications != 0 &&
!existingApp && len(qt.runningApplications)+1 > int(config.maxApplications)) ||
+ (!resources.Equals(resources.NewResource(),
config.maxResources) && resources.StrictlyGreaterThan(finalResourceUsage,
config.maxResources))
+ if wildCardQuotaExceeded {
+ log.Log(log.SchedUGM).Warn("Unable to increase
resource usage as allowing new application to run would exceed either
configured max applications or max resources limit of wild card user/group",
+ zap.Int("tracking type",
int(trackType)),
+ zap.String("queue path", queuePath),
+ zap.Bool("existing app", existingApp),
+ zap.Int("current running applications",
len(qt.runningApplications)),
+ zap.Uint64("max running applications",
config.maxApplications),
+ zap.String("current resource usage",
qt.resourceUsage.String()),
+ zap.String("max resource usage",
config.maxResources.String()))
+ return false
+ }
+ }
+ }
+
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if childQueuePath != "" {
+ if qt.childQueueTrackers[immediateChildQueueName] == nil {
+ qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(immediateChildQueueName, qt)
+ }
+ allowed :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, trackType, usage)
+ if !allowed {
+ return allowed
+ }
+ }
+
qt.resourceUsage.AddTo(usage)
qt.runningApplications[applicationID] = true
log.Log(log.SchedUGM).Debug("Successfully increased resource usage",
+ zap.Int("tracking type", int(trackType)),
zap.String("queue path", queuePath),
zap.String("application", applicationID),
+ zap.Bool("existing app", existingApp),
zap.Stringer("resource", usage),
zap.Stringer("total resource after increasing",
qt.resourceUsage),
zap.Int("total applications after increasing",
len(qt.runningApplications)))
-
- childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
- if childQueuePath != "" {
- if qt.childQueueTrackers[immediateChildQueueName] == nil {
- qt.childQueueTrackers[immediateChildQueueName] =
newQueueTracker(immediateChildQueueName)
- }
- err :=
qt.childQueueTrackers[immediateChildQueueName].increaseTrackedResource(childQueuePath,
applicationID, usage)
- if err != nil {
- return err
- }
- }
- return nil
+ return true
}
-func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, error) {
+func (qt *QueueTracker) decreaseTrackedResource(queuePath string,
applicationID string, usage *resources.Resource, removeApp bool) (bool, bool) {
log.Log(log.SchedUGM).Debug("Decreasing resource usage",
zap.String("queue path", queuePath),
zap.String("application", applicationID),
zap.Stringer("resource", usage),
zap.Bool("removeApp", removeApp))
- if queuePath == "" || usage == nil {
- return false, fmt.Errorf("mandatory parameters are missing.
queuepath: %s, application id: %s, resource usage: %s",
- queuePath, applicationID, usage.String())
- }
- qt.resourceUsage.SubFrom(usage)
- if removeApp {
- delete(qt.runningApplications, applicationID)
- }
- log.Log(log.SchedUGM).Debug("Successfully decreased resource usage",
- zap.String("queue path", queuePath),
- zap.String("application", applicationID),
- zap.Stringer("resource", usage),
- zap.Stringer("total resource after decreasing",
qt.resourceUsage),
- zap.Int("total applications after decreasing",
len(qt.runningApplications)))
-
childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
if childQueuePath != "" {
if qt.childQueueTrackers[immediateChildQueueName] != nil {
- removeQT, err :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
- if err != nil {
- return false, err
+ removeQT, decreased :=
qt.childQueueTrackers[immediateChildQueueName].decreaseTrackedResource(childQueuePath,
applicationID, usage, removeApp)
Review Comment:
Change to == nil and directly return logging the message
##########
pkg/scheduler/ugm/queue_tracker.go:
##########
@@ -201,11 +274,75 @@ func (qt *QueueTracker)
getResourceUsageDAOInfo(parentQueuePath string) *dao.Res
for app := range qt.runningApplications {
usage.RunningApplications = append(usage.RunningApplications,
app)
}
- usage.MaxResources = qt.maxResourceUsage
+ usage.MaxResources = qt.maxResources
usage.MaxApplications = qt.maxRunningApps
for _, cqt := range qt.childQueueTrackers {
childUsage := cqt.getResourceUsageDAOInfo(fullQueuePath)
usage.Children = append(usage.Children, childUsage)
}
return usage
}
+
+// IsQueuePathTrackedCompletely Traverse queue path upto the end queue through
its linkage
+// to confirm entire queuePath has been tracked completely or not
+func (qt *QueueTracker) IsQueuePathTrackedCompletely(queuePath string) bool {
+ if queuePath == configs.RootQueue || queuePath == qt.queueName {
+ return true
+ }
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if immediateChildQueueName != "" {
+ if childUt, ok :=
qt.childQueueTrackers[immediateChildQueueName]; ok {
+ return
childUt.IsQueuePathTrackedCompletely(childQueuePath)
+ }
+ }
+ return false
+}
+
+// IsUnlinkRequired Traverse queue path upto the leaf queue and decide whether
+// linkage needs to be removed or not based on the running applications.
+// If there are any running applications in end leaf queue, we should remove
the linkage between
+// the leaf and its parent queue using UnlinkQT method. Otherwise, we should
leave as it is.
+func (qt *QueueTracker) IsUnlinkRequired(queuePath string) bool {
+ childQueuePath, immediateChildQueueName := getChildQueuePath(queuePath)
+ if immediateChildQueueName != "" {
+ if childUt, ok :=
qt.childQueueTrackers[immediateChildQueueName]; ok {
+ return childUt.IsUnlinkRequired(childQueuePath)
+ }
+ }
+ if queuePath == configs.RootQueue || queuePath == qt.queueName {
+ if len(qt.runningApplications) == 0 {
+ log.Log(log.SchedUGM).Debug("Is Unlink Required?",
+ zap.String("queue path", queuePath),
+ zap.Int("no. of applications",
len(qt.runningApplications)))
+ return true
+ }
+ }
+ return false
+}
+
+// UnlinkQT Traverse queue path upto the end queue. If end queue has any more
child queue trackers,
+// then goes upto each child queue and removes the linkage with its immediate
parent
+func (qt *QueueTracker) UnlinkQT(queuePath string) bool {
Review Comment:
Parent not needed if we use recursive checks.
root.parent.**child**.leaf
-> slice of [root, parent, child, leaf]
```
manager -> user.rootQT.unlinkChild(path []slice)
root.unlinkChild([parent, child, leaf])
root -> find parent
parent.unlinkChild([child.leaf])
parent -> find child
child.unlinkQT([leaf])
if slice.len ==1 leaf can be removed?
delete(qt.childQueueTrackers, leaf.queueName)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]