Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
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
Hide 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.
// Kirill Smelkov <kirr@nexedi.com>
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
//
Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
...
...
@@ -27,7 +27,7 @@ import (
"lab.nexedi.com/kirr/go123/xerr"
)
// Task represents currently running operation
// Task represents currently running operation
.
type
Task
struct
{
Parent
*
Task
Name
string
...
...
@@ -35,17 +35,18 @@ type Task 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
{
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
{
return
Running
(
ctx
,
fmt
.
Sprintf
(
format
,
argv
...
))
}
// Current returns current task represented by context.
//
// if there is no current task - it returns nil.
func
Current
(
ctx
context
.
Context
)
*
Task
{
task
,
_
:=
ctx
.
Value
(
taskKey
{})
.
(
*
Task
)
...
...
@@ -53,6 +54,7 @@ func Current(ctx context.Context) *Task {
}
// ErrContext adds current task name to error on error return.
//
// To work as intended it should be called under defer like this:
//
// func myfunc(ctx, ...) (..., err error) {
...
...
go/xcommon/xcontext/xcontext.go
View file @
00a3c085
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
//
Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
...
...
@@ -18,6 +18,35 @@
// See https://www.nexedi.com/licensing for rationale and options.
// 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
import
(
...
...
@@ -26,6 +55,17 @@ import (
"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.
//
// The result context:
...
...
@@ -36,9 +76,6 @@ import (
//
// Canceling this context releases resources associated with it, so code should
// 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
)
{
mc
:=
&
mergeCtx
{
ctx1
:
ctx1
,
...
...
@@ -47,15 +84,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
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
//
// this saves goroutine spawn and makes
...
...
@@ -80,16 +108,6 @@ func Merge(ctx1, ctx2 context.Context) (context.Context, context.CancelFunc) {
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
func
(
mc
*
mergeCtx
)
wait
()
{
select
{
...
...
@@ -106,18 +124,21 @@ func (mc *mergeCtx) wait() {
close
(
mc
.
done
)
}
// cancel sends signal to wait to shutdown
// cancel is the context.CancelFunc returned for mergeCtx by Merge
// cancel sends signal to wait to shutdown.
//
// cancel is the context.CancelFunc returned for mergeCtx by Merge.
func
(
mc
*
mergeCtx
)
cancel
()
{
mc
.
cancelOnce
.
Do
(
func
()
{
close
(
mc
.
cancelCh
)
})
}
// Done implements context.Context .
func
(
mc
*
mergeCtx
)
Done
()
<-
chan
struct
{}
{
return
mc
.
done
}
// Err implements context.Context .
func
(
mc
*
mergeCtx
)
Err
()
error
{
// synchronize on .done to avoid .doneErr read races
select
{
...
...
@@ -132,6 +153,7 @@ func (mc *mergeCtx) Err() error {
return
mc
.
doneErr
}
// Deadline implements context.Context .
func
(
mc
*
mergeCtx
)
Deadline
()
(
time
.
Time
,
bool
)
{
d1
,
ok1
:=
mc
.
ctx1
.
Deadline
()
d2
,
ok2
:=
mc
.
ctx2
.
Deadline
()
...
...
@@ -147,6 +169,7 @@ func (mc *mergeCtx) Deadline() (time.Time, bool) {
}
}
// Value implements context.Context .
func
(
mc
*
mergeCtx
)
Value
(
key
interface
{})
interface
{}
{
v
:=
mc
.
ctx1
.
Value
(
key
)
if
v
!=
nil
{
...
...
go/xcommon/xcontext/xcontext_test.go
View file @
00a3c085
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
// Copyright (C) 2017
-2018
Nexedi SA and Contributors.
//
Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
...
...
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