Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
isula-build
提交
0d0ca246
I
isula-build
项目概览
openeuler
/
isula-build
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
I
isula-build
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0d0ca246
编写于
8月 12, 2020
作者:
O
openeuler-ci-bot
提交者:
Gitee
8月 12, 2020
浏览文件
操作
浏览文件
下载
差异文件
!33 GC: Use GC to manage subreaper
Merge pull request !33 from holyfei/master
上级
5a59b798
85802df3
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
155 addition
and
112 deletion
+155
-112
daemon/daemon.go
daemon/daemon.go
+24
-19
pkg/gc/gc.go
pkg/gc/gc.go
+62
-46
pkg/gc/gc_test.go
pkg/gc/gc_test.go
+69
-47
未找到文件。
daemon/daemon.go
浏览文件 @
0d0ca246
...
...
@@ -71,16 +71,15 @@ func NewDaemon(opts Options, store store.Store) *Daemon {
// Run runs the daemon process
func
(
d
*
Daemon
)
Run
()
error
{
if
err
:=
d
.
registerSubReaper
();
err
!=
nil
{
return
err
}
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
gc
:=
gc
.
NewGC
()
gc
.
StartGC
(
ctx
)
if
err
:=
d
.
registerSubReaper
(
gc
);
err
!=
nil
{
return
err
}
logrus
.
Debugf
(
"Daemon start with option %#v"
,
d
.
opts
)
// Ensure we have only one daemon running at the same time
...
...
@@ -186,30 +185,36 @@ func (d *Daemon) Cleanup() error {
return
err
}
func
(
d
*
Daemon
)
registerSubReaper
()
error
{
func
(
d
*
Daemon
)
registerSubReaper
(
g
*
gc
.
GarbageCollector
)
error
{
if
err
:=
unix
.
Prctl
(
unix
.
PR_SET_CHILD_SUBREAPER
,
uintptr
(
1
),
0
,
0
,
0
);
err
!=
nil
{
//nolint, gomod
return
errors
.
Errorf
(
"set subreaper failed: %v"
,
err
)
}
go
d
.
childProcessReap
()
return
nil
}
func
(
d
*
Daemon
)
childProcessReap
()
{
reapInterval
:=
10
*
time
.
Second
childProcessReap
:=
func
(
i
interface
{})
error
{
var
err
error
for
{
time
.
Sleep
(
reapInterval
)
d
.
Lock
()
daemonTmp
:=
i
.
(
*
Daemon
)
daemonTmp
.
Lock
()
defer
daemonTmp
.
Unlock
()
// if any of image build process is running, skip reap
if
len
(
d
.
builders
)
!=
0
{
d
.
Unlock
()
continue
if
len
(
daemonTmp
.
builders
)
!=
0
{
return
nil
}
if
err
=
reaper
.
Reap
();
err
!=
nil
{
logrus
.
Errorf
(
"Reap child process error: %v"
,
err
)
}
d
.
Unlock
()
return
err
}
opt
:=
&
gc
.
RegisterOption
{
Name
:
"subReaper"
,
Interval
:
10
*
time
.
Second
,
RecycleData
:
d
,
RecycleFunc
:
childProcessReap
,
}
return
g
.
RegisterGC
(
opt
)
}
// setDaemonLock will check if there is another daemon running and return error if any
...
...
pkg/gc/gc.go
浏览文件 @
0d0ca246
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
* isula-build licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Author: Feiyu Yang
* Create: 2020-06-20
* Description: This file is used for recycling
******************************************************************************/
// Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
// isula-build licensed under the Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v2 for more details.
// Author: Feiyu Yang
// Create: 2020-06-20
// Description: This file is used for recycling
// Package gc provides garbage collectors
package
gc
import
(
...
...
@@ -26,14 +25,21 @@ import (
// RegisterOption is the register option for GC
type
RegisterOption
struct
{
recycleFunc
func
(
interface
{})
error
recycleData
interface
{}
name
string
interval
time
.
Duration
once
bool
// RecycleFunc is the function that can recycle the resource
RecycleFunc
func
(
interface
{})
error
// RecycleData indicates the data to be recycled
RecycleData
interface
{}
// Name indicates the node name
Name
string
// Interval indicates the recycle interval
Interval
time
.
Duration
// Once is true when it is a once time recycle
Once
bool
}
type
node
struct
{
garbageCollector
*
GarbageCollector
name
string
recycleFunc
func
(
interface
{})
error
recycleData
interface
{}
interval
time
.
Duration
...
...
@@ -51,13 +57,15 @@ type GarbageCollector struct {
nodes
map
[
string
]
*
node
}
func
newNode
(
option
*
RegisterOption
)
*
node
{
func
newNode
(
option
*
RegisterOption
,
g
*
GarbageCollector
)
*
node
{
return
&
node
{
recycleFunc
:
option
.
recycleFunc
,
recycleData
:
option
.
recycleData
,
interval
:
option
.
interval
,
garbageCollector
:
g
,
name
:
option
.
Name
,
recycleFunc
:
option
.
RecycleFunc
,
recycleData
:
option
.
RecycleData
,
interval
:
option
.
Interval
,
lastTrigger
:
time
.
Now
(),
once
:
option
.
o
nce
,
once
:
option
.
O
nce
,
}
}
...
...
@@ -70,7 +78,7 @@ func (n *node) isDiscarded() bool {
}
func
(
n
*
node
)
isReadyToRun
(
now
time
.
Time
)
bool
{
if
n
.
isDiscarded
()
||
n
.
running
||
now
.
Sub
(
n
.
lastTrigger
)
<
n
.
interval
{
if
n
.
running
||
now
.
Sub
(
n
.
lastTrigger
)
<
n
.
interval
{
return
false
}
...
...
@@ -81,6 +89,11 @@ func (n *node) checkAndExec(now time.Time) {
n
.
Lock
()
defer
n
.
Unlock
()
if
n
.
isDiscarded
()
{
go
n
.
garbageCollector
.
RemoveGCNode
(
n
.
name
)
return
}
if
!
n
.
isReadyToRun
(
now
)
{
return
}
...
...
@@ -100,8 +113,8 @@ func NewGC() *GarbageCollector {
}
// RegisterGC registers a recycling function
//
o
nce is false when the GC type is loop
//
interval is the i
nterval time in every loop
//
O
nce is false when the GC type is loop
//
Interval is the I
nterval time in every loop
func
(
g
*
GarbageCollector
)
RegisterGC
(
option
*
RegisterOption
)
error
{
if
option
==
nil
{
return
errors
.
New
(
"register option is nil"
)
...
...
@@ -110,13 +123,13 @@ func (g *GarbageCollector) RegisterGC(option *RegisterOption) error {
g
.
Lock
()
defer
g
.
Unlock
()
if
_
,
ok
:=
g
.
nodes
[
option
.
n
ame
];
ok
{
return
errors
.
Errorf
(
"recycle function %s has been registered"
,
option
.
n
ame
)
if
_
,
ok
:=
g
.
nodes
[
option
.
N
ame
];
ok
{
return
errors
.
Errorf
(
"recycle function %s has been registered"
,
option
.
N
ame
)
}
g
.
nodes
[
option
.
name
]
=
newNode
(
option
)
g
.
nodes
[
option
.
Name
]
=
newNode
(
option
,
g
)
logrus
.
Debugf
(
"Recycle function %s is registered successfully"
,
option
.
n
ame
)
logrus
.
Infof
(
"Recycle function %s is registered successfully"
,
option
.
N
ame
)
return
nil
}
...
...
@@ -137,17 +150,20 @@ func (g *GarbageCollector) StartGC(ctx context.Context) {
defer
tick
.
Stop
()
for
{
select
{
case
<-
ctx
.
Done
()
:
case
_
,
ok
:=
<-
ctx
.
Done
()
:
if
!
ok
{
logrus
.
Warnf
(
"Context channel has been closed"
)
}
logrus
.
Debugf
(
"GC exits now"
)
return
case
now
:=
<-
tick
.
C
:
case
now
,
ok
:=
<-
tick
.
C
:
if
!
ok
{
logrus
.
Warnf
(
"Time tick channel has been closed"
)
return
}
g
.
RLock
()
for
name
:=
range
g
.
nodes
{
n
:=
g
.
nodes
[
name
]
if
n
.
isDiscarded
()
{
go
g
.
RemoveGCNode
(
name
)
continue
}
go
n
.
checkAndExec
(
now
)
}
g
.
RUnlock
()
...
...
pkg/gc/gc_test.go
浏览文件 @
0d0ca246
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
* isula-build licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Author: Feiyu Yang
* Create: 2020-06-20
* Description: This file is used for recycling test
******************************************************************************/
// Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
// isula-build licensed under the Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v2 for more details.
// Author: Feiyu Yang
// Create: 2020-06-20
// Description: This file is used for recycling test
package
gc
import
(
"context"
"sync"
"testing"
"time"
...
...
@@ -27,6 +26,7 @@ import (
type
mockDaemon
struct
{
backend
*
mockBackend
opts
string
sync
.
RWMutex
}
type
mockBackend
struct
{
...
...
@@ -62,10 +62,10 @@ func TestGCRoutineExit(t *testing.T) {
return
nil
}
registerOption
:=
&
RegisterOption
{
n
ame
:
"routineExit"
,
r
ecycleFunc
:
f
,
r
ecycleData
:
d
,
i
nterval
:
2
*
time
.
Second
,
N
ame
:
"routineExit"
,
R
ecycleFunc
:
f
,
R
ecycleData
:
d
,
I
nterval
:
2
*
time
.
Second
,
}
err
:=
gcExit
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
...
...
@@ -74,35 +74,40 @@ func TestGCRoutineExit(t *testing.T) {
cancel
()
time
.
Sleep
(
3
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
emptyBackend
)
gcExit
.
RemoveGCNode
(
registerOption
.
n
ame
)
gcExit
.
RemoveGCNode
(
registerOption
.
N
ame
)
}
func
TestLoopGC
(
t
*
testing
.
T
)
{
d
:=
&
mockDaemon
{
backend
:
backend
}
f
:=
func
(
i
interface
{})
error
{
daemon
:=
i
.
(
*
mockDaemon
)
daemon
.
Lock
()
daemon
.
backend
=
emptyBackend
daemon
.
Unlock
()
return
nil
}
registerOption
:=
&
RegisterOption
{
n
ame
:
"recycleBackendResource"
,
r
ecycleFunc
:
f
,
r
ecycleData
:
d
,
i
nterval
:
time
.
Second
,
N
ame
:
"recycleBackendResource"
,
R
ecycleFunc
:
f
,
R
ecycleData
:
d
,
I
nterval
:
time
.
Second
,
}
// register recycleBackendStore and the backend resource will be released
err
:=
gc
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
time
.
Sleep
(
2
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
emptyBackend
)
d
.
RLock
()
b
:=
d
.
backend
d
.
RUnlock
()
assert
.
Equal
(
t
,
b
,
emptyBackend
)
// the same
n
ame has been registered
// the same
N
ame has been registered
err
=
gc
.
RegisterGC
(
registerOption
)
assert
.
ErrorContains
(
t
,
err
,
"has been registered"
)
// remove success and the resource won't be recycled again
gc
.
RemoveGCNode
(
registerOption
.
n
ame
)
gc
.
RemoveGCNode
(
registerOption
.
N
ame
)
d
.
backend
=
backend
time
.
Sleep
(
2
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
backend
)
...
...
@@ -110,16 +115,21 @@ func TestLoopGC(t *testing.T) {
// new recycle func will be registered success
f2
:=
func
(
i
interface
{})
error
{
daemon
:=
i
.
(
*
mockDaemon
)
daemon
.
Lock
()
daemon
.
opts
=
"ok"
daemon
.
Unlock
()
return
nil
}
registerOption
.
n
ame
=
"recycleOpts"
registerOption
.
r
ecycleFunc
=
f2
registerOption
.
N
ame
=
"recycleOpts"
registerOption
.
R
ecycleFunc
=
f2
err
=
gc
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
time
.
Sleep
(
2
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
opts
,
"ok"
)
gc
.
RemoveGCNode
(
registerOption
.
name
)
d
.
RLock
()
opts
:=
d
.
opts
d
.
RUnlock
()
assert
.
Equal
(
t
,
opts
,
"ok"
)
gc
.
RemoveGCNode
(
registerOption
.
Name
)
}
func
TestOnceGC
(
t
*
testing
.
T
)
{
...
...
@@ -128,11 +138,11 @@ func TestOnceGC(t *testing.T) {
return
errors
.
New
(
"recycle failed"
)
}
registerOption
:=
&
RegisterOption
{
n
ame
:
"recycleTestErr"
,
r
ecycleFunc
:
f
,
r
ecycleData
:
d
,
i
nterval
:
time
.
Second
,
o
nce
:
true
,
N
ame
:
"recycleTestErr"
,
R
ecycleFunc
:
f
,
R
ecycleData
:
d
,
I
nterval
:
time
.
Second
,
O
nce
:
true
,
}
// register a gc which will always return error
err
:=
gc
.
RegisterGC
(
registerOption
)
...
...
@@ -142,52 +152,64 @@ func TestOnceGC(t *testing.T) {
// register will failed
err
=
gc
.
RegisterGC
(
registerOption
)
assert
.
ErrorContains
(
t
,
err
,
"has been registered"
)
gc
.
RemoveGCNode
(
registerOption
.
n
ame
)
gc
.
RemoveGCNode
(
registerOption
.
N
ame
)
d
.
backend
=
&
mockBackend
{
status
:
map
[
string
]
string
{
"
once"
:
"o
nce"
}}
d
.
backend
=
&
mockBackend
{
status
:
map
[
string
]
string
{
"
Once"
:
"O
nce"
}}
// register a normal gc
f2
:=
func
(
i
interface
{})
error
{
daemon
:=
i
.
(
*
mockDaemon
)
daemon
.
Lock
()
daemon
.
backend
=
emptyBackend
daemon
.
Unlock
()
return
nil
}
registerOption
.
name
=
"o
nce"
registerOption
.
r
ecycleFunc
=
f2
registerOption
.
Name
=
"O
nce"
registerOption
.
R
ecycleFunc
=
f2
err
=
gc
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
time
.
Sleep
(
4
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
emptyBackend
)
d
.
RLock
()
b
:=
d
.
backend
d
.
RUnlock
()
assert
.
Equal
(
t
,
b
,
emptyBackend
)
// the last normal gc has been removed after executing,
// new gc will be registered successfully
err
=
gc
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
gc
.
RemoveGCNode
(
registerOption
.
n
ame
)
gc
.
RemoveGCNode
(
registerOption
.
N
ame
)
}
func
TestGCAlreadyInRunning
(
t
*
testing
.
T
)
{
d
:=
&
mockDaemon
{
backend
:
backend
}
f
:=
func
(
i
interface
{})
error
{
daemon
:=
i
.
(
*
mockDaemon
)
daemon
.
Lock
()
daemon
.
backend
=
emptyBackend
daemon
.
Unlock
()
time
.
Sleep
(
30
*
time
.
Second
)
return
nil
}
registerOption
:=
&
RegisterOption
{
n
ame
:
"recycleSlow"
,
r
ecycleFunc
:
f
,
r
ecycleData
:
d
,
i
nterval
:
time
.
Second
,
N
ame
:
"recycleSlow"
,
R
ecycleFunc
:
f
,
R
ecycleData
:
d
,
I
nterval
:
time
.
Second
,
}
err
:=
gc
.
RegisterGC
(
registerOption
)
assert
.
NilError
(
t
,
err
)
time
.
Sleep
(
2
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
emptyBackend
)
d
.
RLock
()
b
:=
d
.
backend
d
.
RUnlock
()
assert
.
Equal
(
t
,
b
,
emptyBackend
)
// a recycling work is doing and it won't be triggered now
d
.
RLock
()
d
.
backend
=
backend
d
.
RUnlock
()
time
.
Sleep
(
2
*
time
.
Second
)
assert
.
Equal
(
t
,
d
.
backend
,
backend
)
gc
.
RemoveGCNode
(
registerOption
.
n
ame
)
gc
.
RemoveGCNode
(
registerOption
.
N
ame
)
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录