Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
00a3c085
Commit
00a3c085
authored
May 25, 2018
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
60125d35
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
58 additions
and
33 deletions
+58
-33
go/xcommon/xcontext/task/task.go
go/xcommon/xcontext/task/task.go
+7
-5
go/xcommon/xcontext/xcontext.go
go/xcommon/xcontext/xcontext.go
+49
-26
go/xcommon/xcontext/xcontext_test.go
go/xcommon/xcontext/xcontext_test.go
+2
-2
No files found.
go/xcommon/xcontext/task/task.go
View file @
00a3c085
// Copyright (C) 2017 Nexedi SA and Contributors.
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
// Kirill Smelkov <kirr@nexedi.com>
//
//
// This program is free software: you can Use, Study, Modify and Redistribute
// This program is free software: you can Use, Study, Modify and Redistribute
...
@@ -27,7 +27,7 @@ import (
...
@@ -27,7 +27,7 @@ import (
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xerr"
)
)
// Task represents currently running operation
// Task represents currently running operation
.
type
Task
struct
{
type
Task
struct
{
Parent
*
Task
Parent
*
Task
Name
string
Name
string
...
@@ -35,17 +35,18 @@ type Task struct {
...
@@ -35,17 +35,18 @@ type Task struct {
type
taskKey
struct
{}
type
taskKey
struct
{}
// Running creates new task and returns new context with that task set to current
// Running creates new task and returns new context with that task set to current
.
func
Running
(
ctx
context
.
Context
,
name
string
)
context
.
Context
{
func
Running
(
ctx
context
.
Context
,
name
string
)
context
.
Context
{
return
context
.
WithValue
(
ctx
,
taskKey
{},
&
Task
{
Parent
:
Current
(
ctx
),
Name
:
name
})
return
context
.
WithValue
(
ctx
,
taskKey
{},
&
Task
{
Parent
:
Current
(
ctx
),
Name
:
name
})
}
}
// Runningf is Running cousin with formatting support
// Runningf is Running cousin with formatting support
.
func
Runningf
(
ctx
context
.
Context
,
format
string
,
argv
...
interface
{})
context
.
Context
{
func
Runningf
(
ctx
context
.
Context
,
format
string
,
argv
...
interface
{})
context
.
Context
{
return
Running
(
ctx
,
fmt
.
Sprintf
(
format
,
argv
...
))
return
Running
(
ctx
,
fmt
.
Sprintf
(
format
,
argv
...
))
}
}
// Current returns current task represented by context.
// Current returns current task represented by context.
//
// if there is no current task - it returns nil.
// if there is no current task - it returns nil.
func
Current
(
ctx
context
.
Context
)
*
Task
{
func
Current
(
ctx
context
.
Context
)
*
Task
{
task
,
_
:=
ctx
.
Value
(
taskKey
{})
.
(
*
Task
)
task
,
_
:=
ctx
.
Value
(
taskKey
{})
.
(
*
Task
)
...
@@ -53,6 +54,7 @@ func Current(ctx context.Context) *Task {
...
@@ -53,6 +54,7 @@ func Current(ctx context.Context) *Task {
}
}
// ErrContext adds current task name to error on error return.
// ErrContext adds current task name to error on error return.
//
// To work as intended it should be called under defer like this:
// To work as intended it should be called under defer like this:
//
//
// func myfunc(ctx, ...) (..., err error) {
// func myfunc(ctx, ...) (..., err error) {
...
...
go/xcommon/xcontext/xcontext.go
View file @
00a3c085
// Copyright (C) 2017 Nexedi SA and Contributors.
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
// Kirill Smelkov <kirr@nexedi.com>
//
//
// This program is free software: you can Use, Study, Modify and Redistribute
// This program is free software: you can Use, Study, Modify and Redistribute
...
@@ -18,6 +18,35 @@
...
@@ -18,6 +18,35 @@
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
// Package xcontext provides addons to std package context.
// Package xcontext provides addons to std package context.
//
// Merging contexts
//
// Merge and MergeChan could be handy in situations where spawned job needs to
// be canceled whenever any of 2 contexts becomes done. This frequently arises
// with service methods which accept context as argument, and the service
// itself, on another control line, could be instructed to become
// non-operational. For example:
//
// func (srv *Service) DoSomething(ctx context.Context) error {
// // srv.down is chan struct{} that becomes ready when service is closed.
// ctxDown, down := xcontext.MergeChan(ctx, srv.down)
// defer down()
//
// err := doJob(ctxDown)
// if ctxDown.Err() != nil && ctx.Err() == nil {
// err = ErrDueToServiceDown
// }
//
// ...
// }
//
//
//
// XXX docs:
// - Canceled
// - Merge
//
// - WhenDone
package
xcontext
package
xcontext
import
(
import
(
...
@@ -26,6 +55,17 @@ import (
...
@@ -26,6 +55,17 @@ import (
"time"
"time"
)
)
// mergeCtx represents 2 context merged into 1.
type
mergeCtx
struct
{
ctx1
,
ctx2
context
.
Context
done
chan
struct
{}
doneErr
error
cancelCh
chan
struct
{}
cancelOnce
sync
.
Once
}
// Merge merges 2 contexts into 1.
// Merge merges 2 contexts into 1.
//
//
// The result context:
// The result context:
...
@@ -36,9 +76,6 @@ import (
...
@@ -36,9 +76,6 @@ import (
//
//
// Canceling this context releases resources associated with it, so code should
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
// call cancel as soon as the operations running in this Context complete.
//
// XXX let Merge do only merge, not create another cancel; optimize it for
// cases when a source context is not cancellable
func
Merge
(
ctx1
,
ctx2
context
.
Context
)
(
context
.
Context
,
context
.
CancelFunc
)
{
func
Merge
(
ctx1
,
ctx2
context
.
Context
)
(
context
.
Context
,
context
.
CancelFunc
)
{
mc
:=
&
mergeCtx
{
mc
:=
&
mergeCtx
{
ctx1
:
ctx1
,
ctx1
:
ctx1
,
...
@@ -47,15 +84,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
...
@@ -47,15 +84,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
cancelCh
:
make
(
chan
struct
{}),
cancelCh
:
make
(
chan
struct
{}),
}
}
/*
// ctx1 will never be canceled?
switch ctx1.Done() {
case nil, context.Background().Done():
bg1 = true
}
// ----//---- same for ctx2?
*/
// if src ctx is already cancelled - make mc cancelled right after creation
// if src ctx is already cancelled - make mc cancelled right after creation
//
//
// this saves goroutine spawn and makes
// this saves goroutine spawn and makes
...
@@ -80,16 +108,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
...
@@ -80,16 +108,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
return
mc
,
mc
.
cancel
return
mc
,
mc
.
cancel
}
}
type
mergeCtx
struct
{
ctx1
,
ctx2
context
.
Context
done
chan
struct
{}
doneErr
error
cancelCh
chan
struct
{}
cancelOnce
sync
.
Once
}
// wait waits when .ctx1 or .ctx2 is done and then mark mergeCtx as done
// wait waits when .ctx1 or .ctx2 is done and then mark mergeCtx as done
func
(
mc
*
mergeCtx
)
wait
()
{
func
(
mc
*
mergeCtx
)
wait
()
{
select
{
select
{
...
@@ -106,18 +124,21 @@ func (mc *mergeCtx) wait() {
...
@@ -106,18 +124,21 @@ func (mc *mergeCtx) wait() {
close
(
mc
.
done
)
close
(
mc
.
done
)
}
}
// cancel sends signal to wait to shutdown
// cancel sends signal to wait to shutdown.
// cancel is the context.CancelFunc returned for mergeCtx by Merge
//
// cancel is the context.CancelFunc returned for mergeCtx by Merge.
func
(
mc
*
mergeCtx
)
cancel
()
{
func
(
mc
*
mergeCtx
)
cancel
()
{
mc
.
cancelOnce
.
Do
(
func
()
{
mc
.
cancelOnce
.
Do
(
func
()
{
close
(
mc
.
cancelCh
)
close
(
mc
.
cancelCh
)
})
})
}
}
// Done implements context.Context .
func
(
mc
*
mergeCtx
)
Done
()
<-
chan
struct
{}
{
func
(
mc
*
mergeCtx
)
Done
()
<-
chan
struct
{}
{
return
mc
.
done
return
mc
.
done
}
}
// Err implements context.Context .
func
(
mc
*
mergeCtx
)
Err
()
error
{
func
(
mc
*
mergeCtx
)
Err
()
error
{
// synchronize on .done to avoid .doneErr read races
// synchronize on .done to avoid .doneErr read races
select
{
select
{
...
@@ -132,6 +153,7 @@ func (mc *mergeCtx) Err() error {
...
@@ -132,6 +153,7 @@ func (mc *mergeCtx) Err() error {
return
mc
.
doneErr
return
mc
.
doneErr
}
}
// Deadline implements context.Context .
func
(
mc
*
mergeCtx
)
Deadline
()
(
time
.
Time
,
bool
)
{
func
(
mc
*
mergeCtx
)
Deadline
()
(
time
.
Time
,
bool
)
{
d1
,
ok1
:=
mc
.
ctx1
.
Deadline
()
d1
,
ok1
:=
mc
.
ctx1
.
Deadline
()
d2
,
ok2
:=
mc
.
ctx2
.
Deadline
()
d2
,
ok2
:=
mc
.
ctx2
.
Deadline
()
...
@@ -147,6 +169,7 @@ func (mc *mergeCtx) Deadline() (time.Time, bool) {
...
@@ -147,6 +169,7 @@ func (mc *mergeCtx) Deadline() (time.Time, bool) {
}
}
}
}
// Value implements context.Context .
func
(
mc
*
mergeCtx
)
Value
(
key
interface
{})
interface
{}
{
func
(
mc
*
mergeCtx
)
Value
(
key
interface
{})
interface
{}
{
v
:=
mc
.
ctx1
.
Value
(
key
)
v
:=
mc
.
ctx1
.
Value
(
key
)
if
v
!=
nil
{
if
v
!=
nil
{
...
...
go/xcommon/xcontext/xcontext_test.go
View file @
00a3c085
// Copyright (C) 2017 Nexedi SA and Contributors.
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
// Kirill Smelkov <kirr@nexedi.com>
//
//
// This program is free software: you can Use, Study, Modify and Redistribute
// This program is free software: you can Use, Study, Modify and Redistribute
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment