Merge branch 'patch-1' of https://github.com/mr-c/arvados into mr-c-patch-1
[arvados.git] / sdk / go / arvadosclient / pool.go
index 87b67c39b67c6f3ee95a165f9cc50f83ba5be3a7..bb7867aef7e35d283c5e47adb68873492bda609c 100644 (file)
@@ -1,7 +1,13 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
 package arvadosclient
 
 import (
        "sync"
+
+       "git.arvados.org/arvados.git/sdk/go/arvados"
 )
 
 // A ClientPool is a pool of ArvadosClients. This is useful for
@@ -10,22 +16,45 @@ import (
 // credentials. See arvados-git-httpd for an example, and sync.Pool
 // for more information about garbage collection.
 type ClientPool struct {
-       sync.Pool
-       lastErr error
+       // Initialize new clients by copying this one.
+       Prototype *ArvadosClient
+
+       pool      *sync.Pool
+       lastErr   error
+       setupOnce sync.Once
 }
 
-// MakeClientPool returns a new empty ClientPool.
+// MakeClientPool returns a new empty ClientPool, using environment
+// variables to initialize the prototype.
 func MakeClientPool() *ClientPool {
-       p := &ClientPool{}
-       p.Pool = sync.Pool{New: func() interface{} {
-               arv, err := MakeArvadosClient()
-               if err != nil {
-                       p.lastErr = err
+       return MakeClientPoolWith(nil)
+}
+
+// MakeClientPoolWith returns a new empty ClientPool with a previously
+// initialized arvados.Client.
+func MakeClientPoolWith(client *arvados.Client) *ClientPool {
+       var err error
+       var proto *ArvadosClient
+
+       if client == nil {
+               proto, err = MakeArvadosClient()
+       } else {
+               proto, err = New(client)
+       }
+       return &ClientPool{
+               Prototype: proto,
+               lastErr:   err,
+       }
+}
+
+func (p *ClientPool) setup() {
+       p.pool = &sync.Pool{New: func() interface{} {
+               if p.lastErr != nil {
                        return nil
                }
-               return &arv
+               c := *p.Prototype
+               return &c
        }}
-       return p
 }
 
 // Err returns the error that was encountered last time Get returned
@@ -39,7 +68,8 @@ func (p *ClientPool) Err() error {
 // (including its ApiToken) will be just as it was when it was Put
 // back in the pool.
 func (p *ClientPool) Get() *ArvadosClient {
-       c, ok := p.Pool.Get().(*ArvadosClient)
+       p.setupOnce.Do(p.setup)
+       c, ok := p.pool.Get().(*ArvadosClient)
        if !ok {
                return nil
        }
@@ -48,5 +78,6 @@ func (p *ClientPool) Get() *ArvadosClient {
 
 // Put puts an ArvadosClient back in the pool.
 func (p *ClientPool) Put(c *ArvadosClient) {
-       p.Pool.Put(c)
+       p.setupOnce.Do(p.setup)
+       p.pool.Put(c)
 }