Adds 2 new methods to v2 plugin `Acquire` and `Release` which allow
refcounting directly at the plugin level instead of just the store.
Since a graphdriver is initialized exactly once, and is really managed
by a separate object, it didn't really seem right to call
`getter.Get()` to refcount graphdriver plugins.
On shutdown it was particularly weird where we'd either need to keep a
driver reference in daemon, or keep a reference to the pluggin getter in
the layer store, and even then still store extra details on if the
graphdriver is a plugin or not.
Instead the plugin proxy itself will handle calling the neccessary
refcounting methods directly on the plugin object.
Also adds a new interface in `plugingetter` to account for these new
functions which are not going to be implemented by v1 plugins.
Changes terms `plugingetter.CREATE` and `plugingetter.REMOVE` to
`ACQUIRE` and `RELEASE` respectively, which seems to be better
adjectives for what we're doing.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -22,10 +22,10 @@ func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter |
| 22 | 22 |
if err != nil {
|
| 23 | 23 |
return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err)
|
| 24 | 24 |
} |
| 25 |
- return newPluginDriver(name, home, opts, pl.Client()) |
|
| 25 |
+ return newPluginDriver(name, home, opts, pl) |
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
-func newPluginDriver(name, home string, opts []string, c pluginClient) (Driver, error) {
|
|
| 29 |
- proxy := &graphDriverProxy{name, c}
|
|
| 28 |
+func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlugin) (Driver, error) {
|
|
| 29 |
+ proxy := &graphDriverProxy{name, pl.Client(), pl}
|
|
| 30 | 30 |
return proxy, proxy.Init(filepath.Join(home, name), opts) |
| 31 | 31 |
} |
| ... | ... |
@@ -6,11 +6,13 @@ import ( |
| 6 | 6 |
"io" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/pkg/archive" |
| 9 |
+ "github.com/docker/docker/pkg/plugingetter" |
|
| 9 | 10 |
) |
| 10 | 11 |
|
| 11 | 12 |
type graphDriverProxy struct {
|
| 12 | 13 |
name string |
| 13 | 14 |
client pluginClient |
| 15 |
+ p plugingetter.CompatPlugin |
|
| 14 | 16 |
} |
| 15 | 17 |
|
| 16 | 18 |
type graphDriverRequest struct {
|
| ... | ... |
@@ -35,6 +37,12 @@ type graphDriverInitRequest struct {
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 | 37 |
func (d *graphDriverProxy) Init(home string, opts []string) error {
|
| 38 |
+ if !d.p.IsV1() {
|
|
| 39 |
+ if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
|
|
| 40 |
+ // always acquire here, it will be cleaned up on daemon shutdown |
|
| 41 |
+ cp.Acquire() |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 38 | 44 |
args := &graphDriverInitRequest{
|
| 39 | 45 |
Home: home, |
| 40 | 46 |
Opts: opts, |
| ... | ... |
@@ -167,6 +175,13 @@ func (d *graphDriverProxy) GetMetadata(id string) (map[string]string, error) {
|
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 | 169 |
func (d *graphDriverProxy) Cleanup() error {
|
| 170 |
+ if !d.p.IsV1() {
|
|
| 171 |
+ if cp, ok := d.p.(plugingetter.CountedPlugin); ok {
|
|
| 172 |
+ // always release |
|
| 173 |
+ defer cp.Release() |
|
| 174 |
+ } |
|
| 175 |
+ } |
|
| 176 |
+ |
|
| 170 | 177 |
args := &graphDriverRequest{}
|
| 171 | 178 |
var ret graphDriverResponse |
| 172 | 179 |
if err := d.client.Call("GraphDriver.Cleanup", args, &ret); err != nil {
|
| ... | ... |
@@ -5,10 +5,10 @@ import "github.com/docker/docker/pkg/plugins" |
| 5 | 5 |
const ( |
| 6 | 6 |
// LOOKUP doesn't update RefCount |
| 7 | 7 |
LOOKUP = 0 |
| 8 |
- // CREATE increments RefCount |
|
| 9 |
- CREATE = 1 |
|
| 10 |
- // REMOVE decrements RefCount |
|
| 11 |
- REMOVE = -1 |
|
| 8 |
+ // ACQUIRE increments RefCount |
|
| 9 |
+ ACQUIRE = 1 |
|
| 10 |
+ // RELEASE decrements RefCount |
|
| 11 |
+ RELEASE = -1 |
|
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 | 14 |
// CompatPlugin is a abstraction to handle both v2(new) and v1(legacy) plugins. |
| ... | ... |
@@ -19,6 +19,13 @@ type CompatPlugin interface {
|
| 19 | 19 |
IsV1() bool |
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
+// CountedPlugin is a plugin which is reference counted. |
|
| 23 |
+type CountedPlugin interface {
|
|
| 24 |
+ Acquire() |
|
| 25 |
+ Release() |
|
| 26 |
+ CompatPlugin |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 22 | 29 |
// PluginGetter is the interface implemented by Store |
| 23 | 30 |
type PluginGetter interface {
|
| 24 | 31 |
Get(name, capability string, mode int) (CompatPlugin, error) |
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 | 13 |
"github.com/docker/docker/oci" |
| 14 |
+ "github.com/docker/docker/pkg/plugingetter" |
|
| 14 | 15 |
"github.com/docker/docker/pkg/plugins" |
| 15 | 16 |
"github.com/docker/docker/pkg/system" |
| 16 | 17 |
specs "github.com/opencontainers/runtime-spec/specs-go" |
| ... | ... |
@@ -294,6 +295,19 @@ func (p *Plugin) AddRefCount(count int) {
|
| 294 | 294 |
p.refCount += count |
| 295 | 295 |
} |
| 296 | 296 |
|
| 297 |
+// Acquire increments the plugin's reference count |
|
| 298 |
+// This should be followed up by `Release()` when the plugin is no longer in use. |
|
| 299 |
+func (p *Plugin) Acquire() {
|
|
| 300 |
+ p.AddRefCount(plugingetter.ACQUIRE) |
|
| 301 |
+} |
|
| 302 |
+ |
|
| 303 |
+// Release decrements the plugin's reference count |
|
| 304 |
+// This should only be called when the plugin is no longer in use, e.g. with |
|
| 305 |
+// via `Acquire()` or getter.Get("name", "type", plugingetter.ACQUIRE)
|
|
| 306 |
+func (p *Plugin) Release() {
|
|
| 307 |
+ p.AddRefCount(plugingetter.RELEASE) |
|
| 308 |
+} |
|
| 309 |
+ |
|
| 297 | 310 |
// InitSpec creates an OCI spec from the plugin's config. |
| 298 | 311 |
func (p *Plugin) InitSpec(s specs.Spec) (*specs.Spec, error) {
|
| 299 | 312 |
s.Root = specs.Root{
|
| ... | ... |
@@ -153,7 +153,7 @@ func CreateDriver(name string) (volume.Driver, error) {
|
| 153 | 153 |
if name == "" {
|
| 154 | 154 |
name = volume.DefaultDriverName |
| 155 | 155 |
} |
| 156 |
- return lookup(name, getter.CREATE) |
|
| 156 |
+ return lookup(name, getter.ACQUIRE) |
|
| 157 | 157 |
} |
| 158 | 158 |
|
| 159 | 159 |
// RemoveDriver returns a volume driver by its name and decrements RefCount.. |
| ... | ... |
@@ -162,7 +162,7 @@ func RemoveDriver(name string) (volume.Driver, error) {
|
| 162 | 162 |
if name == "" {
|
| 163 | 163 |
name = volume.DefaultDriverName |
| 164 | 164 |
} |
| 165 |
- return lookup(name, getter.REMOVE) |
|
| 165 |
+ return lookup(name, getter.RELEASE) |
|
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 | 168 |
// GetDriverList returns list of volume drivers registered. |