From f7d9bc26368763d9c0bc9e7fc462dc0ab99a1784 Mon Sep 17 00:00:00 2001
From: hanchao <hanchao63@huawei.com>
Date: Fri, 16 Jun 2023 13:10:42 +0800
Subject: [PATCH 06/13] rubik: fix that value of memory.high_async_ratio lost
 efficacy

---
 pkg/services/dynmemory/dynmemory.go | 22 +++++++-
 pkg/services/dynmemory/fssr.go      | 78 +++++++++++++++++------------
 2 files changed, 67 insertions(+), 33 deletions(-)

diff --git a/pkg/services/dynmemory/dynmemory.go b/pkg/services/dynmemory/dynmemory.go
index da859dd..b73f476 100644
--- a/pkg/services/dynmemory/dynmemory.go
+++ b/pkg/services/dynmemory/dynmemory.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"isula.org/rubik/pkg/api"
+	"isula.org/rubik/pkg/core/typedef"
 	"isula.org/rubik/pkg/services/helper"
 	"k8s.io/apimachinery/pkg/util/wait"
 )
@@ -15,6 +16,7 @@ type DynMemoryAdapter interface {
 	preStart(api.Viewer) error
 	getInterval() int
 	dynamicAdjust()
+	setOfflinePod(path string) error
 }
 type dynMemoryConfig struct {
 	Policy string `json:"policy,omitempty"`
@@ -42,11 +44,11 @@ type DynMemory struct {
 }
 
 // PreStart is an interface for calling a collection of methods when the service is pre-started
-func (dynMem *DynMemory) PreStart(api api.Viewer) error {
+func (dynMem *DynMemory) PreStart(viewer api.Viewer) error {
 	if dynMem.dynMemoryAdapter == nil {
 		return nil
 	}
-	return dynMem.dynMemoryAdapter.preStart(api)
+	return dynMem.dynMemoryAdapter.preStart(viewer)
 }
 
 // SetConfig is an interface that invoke the ConfigHandler to obtain the corresponding configuration.
@@ -81,6 +83,22 @@ func (dynMem *DynMemory) IsRunner() bool {
 	return true
 }
 
+// AddPod to deal the event of adding a pod.
+func (dynMem *DynMemory) AddPod(podInfo *typedef.PodInfo) error {
+	if podInfo.Offline() {
+		return dynMem.dynMemoryAdapter.setOfflinePod(podInfo.Path)
+	}
+	return nil
+}
+
+// UpdatePod to deal the pod update event.
+func (dynMem *DynMemory) UpdatePod(old, new *typedef.PodInfo) error {
+	if new.Offline() {
+		return dynMem.dynMemoryAdapter.setOfflinePod(new.Path)
+	}
+	return nil
+}
+
 // newAdapter to create adapter of dyn memory.
 func newAdapter(policy string) DynMemoryAdapter {
 	switch policy {
diff --git a/pkg/services/dynmemory/fssr.go b/pkg/services/dynmemory/fssr.go
index 9fe4042..e23a4bc 100644
--- a/pkg/services/dynmemory/fssr.go
+++ b/pkg/services/dynmemory/fssr.go
@@ -9,6 +9,7 @@ import (
 
 	"isula.org/rubik/pkg/api"
 	"isula.org/rubik/pkg/common/constant"
+	"isula.org/rubik/pkg/common/log"
 	"isula.org/rubik/pkg/common/util"
 	"isula.org/rubik/pkg/core/typedef"
 	"isula.org/rubik/pkg/core/typedef/cgroup"
@@ -30,71 +31,76 @@ type fssrDynMemAdapter struct {
 	memTotal    int64
 	memHigh     int64
 	reservedMem int64
-	api         api.Viewer
 	count       int64
+	viewer      api.Viewer
 }
 
-// initFssrDynMemAdapter function
+// initFssrDynMemAdapter initializes a new fssrDynMemAdapter struct.
 func initFssrDynMemAdapter() *fssrDynMemAdapter {
 	if total, err := getFieldMemory("MemTotal"); err == nil && total > 0 {
 		return &fssrDynMemAdapter{
 			memTotal:    total,
 			memHigh:     total * 8 / 10,
-			reservedMem: total * 8 / 10,
+			reservedMem: total * 1 / 10,
+			count:       0,
 		}
 	}
 	return nil
 }
 
-// preStart function
-func (f *fssrDynMemAdapter) preStart(api api.Viewer) error {
-	f.api = api
+// preStart initializes the fssrDynMemAdapter with the provided viewer and
+// deals with any existing pods.
+func (f *fssrDynMemAdapter) preStart(viewer api.Viewer) error {
+	f.viewer = viewer
 	return f.dealExistedPods()
 }
 
-// getInterval function
+// getInterval returns the fssrInterval value.
 func (f *fssrDynMemAdapter) getInterval() int {
 	return fssrInterval
 }
 
-// dynadjust function
+// dynamicAdjust adjusts the memory allocation of the fssrDynMemAdapter by
+// increasing or decreasing the amount of memory reserved for offline pods
+// based on the current amount of free memory available on the system.
 func (f *fssrDynMemAdapter) dynamicAdjust() {
 	var freeMem int64
 	var err error
 	if freeMem, err = getFieldMemory("MemFree"); err != nil {
 		return
 	}
+
+	var memHigh int64 = 0
 	if freeMem > 2*f.reservedMem {
 		if f.count < fssrIntervalCount {
 			f.count++
 			return
 		}
-		memHigh := f.memHigh + f.memTotal/100
+		// no risk of overflow
+		memHigh = f.memHigh + f.memTotal/100
 		if memHigh > f.memTotal*8/10 {
 			memHigh = f.memTotal * 8 / 10
 		}
-		if memHigh != f.memHigh {
-			f.memHigh = memHigh
-			f.adjustOfflinePodHighMemory()
-		}
 	} else if freeMem < f.reservedMem {
-		memHigh := f.memHigh - f.memTotal/10
+		memHigh = f.memHigh - f.memTotal/10
 		if memHigh < 0 {
 			return
 		}
 		if memHigh < f.memTotal*3/10 {
 			memHigh = f.memTotal * 3 / 10
 		}
-		if memHigh != f.memHigh {
-			f.memHigh = memHigh
-			f.adjustOfflinePodHighMemory()
-		}
 	}
+	if memHigh != f.memHigh {
+		f.memHigh = memHigh
+		f.adjustOfflinePodHighMemory()
+	}
+
 	f.count = 0
 }
 
+// adjustOfflinePodHighMemory adjusts the memory.high of offline pods.
 func (f *fssrDynMemAdapter) adjustOfflinePodHighMemory() error {
-	pods := listOfflinePods(f.api)
+	pods := listOfflinePods(f.viewer)
 	for _, podInfo := range pods {
 		if err := setOfflinePodHighMemory(podInfo.Path, f.memHigh); err != nil {
 			return err
@@ -103,20 +109,18 @@ func (f *fssrDynMemAdapter) adjustOfflinePodHighMemory() error {
 	return nil
 }
 
-// dealExistedPods function
+// dealExistedPods handles offline pods by setting their memory.high and memory.high_async_ratio
 func (f *fssrDynMemAdapter) dealExistedPods() error {
-	pods := listOfflinePods(f.api)
+	pods := listOfflinePods(f.viewer)
 	for _, podInfo := range pods {
-		if err := setOfflinePodHighMemory(podInfo.Path, f.memHigh); err != nil {
-			return err
-		}
-		if err := setOfflinePodHighAsyncRatio(podInfo.Path, highRatio); err != nil {
-			return err
+		if err := f.setOfflinePod(podInfo.Path); err != nil {
+			log.Errorf("set fssr of offline pod[%v] error:%v", podInfo.UID, err)
 		}
 	}
 	return nil
 }
 
+// listOfflinePods returns a map of offline PodInfo objects.
 func listOfflinePods(viewer api.Viewer) map[string]*typedef.PodInfo {
 	offlineValue := "true"
 	return viewer.ListPodsWithOptions(func(pi *typedef.PodInfo) bool {
@@ -124,23 +128,35 @@ func listOfflinePods(viewer api.Viewer) map[string]*typedef.PodInfo {
 	})
 }
 
-func setOfflinePodHighMemory(podPath string, high int64) error {
-	if err := cgroup.WriteCgroupFile(strconv.FormatUint(uint64(high), scale), memcgRootDir,
+// setOfflinePod sets the offline pod for the given path.
+func (f *fssrDynMemAdapter) setOfflinePod(path string) error {
+	if err := setOfflinePodHighAsyncRatio(path, highRatio); err != nil {
+		return err
+	}
+	return setOfflinePodHighMemory(path, f.memHigh)
+}
+
+// setOfflinePodHighMemory sets the high memory limit for the specified pod in the
+// cgroup memory
+func setOfflinePodHighMemory(podPath string, memHigh int64) error {
+	if err := cgroup.WriteCgroupFile(strconv.FormatUint(uint64(memHigh), scale), memcgRootDir,
 		podPath, highMemFile); err != nil {
 		return err
 	}
 	return nil
 }
 
-func setOfflinePodHighAsyncRatio(podPath string, ratio uint64) error {
-	if err := cgroup.WriteCgroupFile(strconv.FormatUint(ratio, scale), memcgRootDir,
+// setOfflinePodHighAsyncRatio sets the high memory async ratio for a pod in an offline state.
+func setOfflinePodHighAsyncRatio(podPath string, ratio uint) error {
+	if err := cgroup.WriteCgroupFile(strconv.FormatUint(uint64(ratio), scale), memcgRootDir,
 		podPath, highMemAsyncRatioFile); err != nil {
 		return err
 	}
 	return nil
 }
 
-// getFieldMemory function
+// getFieldMemory retrieves the amount of memory used by a certain field in the
+// memory information file.
 func getFieldMemory(field string) (int64, error) {
 	if !util.PathExist(memInfoFile) {
 		return 0, fmt.Errorf("%v: no such file or diretory", memInfoFile)
-- 
2.41.0

