5824: Move HTTP server code to SDK.
[arvados.git] / sdk / go / keepclient / keepclient.go
index 853f4c61eff69f26311d196a38b35588758ef16c..f82e5c7c594062f23da7ab42db3c4971738d5597 100644 (file)
@@ -24,7 +24,7 @@ const BLOCKSIZE = 64 * 1024 * 1024
 
 var BlockNotFound = errors.New("Block not found")
 var InsufficientReplicasError = errors.New("Could not write sufficient replicas")
-var OversizeBlockError = errors.New("Exceeded maximum block size ("+strconv.Itoa(BLOCKSIZE)+")")
+var OversizeBlockError = errors.New("Exceeded maximum block size (" + strconv.Itoa(BLOCKSIZE) + ")")
 var MissingArvadosApiHost = errors.New("Missing required environment variable ARVADOS_API_HOST")
 var MissingArvadosApiToken = errors.New("Missing required environment variable ARVADOS_API_TOKEN")
 var InvalidLocatorError = errors.New("Invalid locator")
@@ -38,6 +38,7 @@ type KeepClient struct {
        Want_replicas int
        Using_proxy   bool
        localRoots    *map[string]string
+       writableLocalRoots *map[string]string
        gatewayRoots  *map[string]string
        lock          sync.RWMutex
        Client        *http.Client
@@ -126,7 +127,7 @@ func (kc *KeepClient) PutR(r io.Reader) (locator string, replicas int, err error
 func (kc *KeepClient) Get(locator string) (io.ReadCloser, int64, string, error) {
        var errs []string
        for _, host := range kc.getSortedRoots(locator) {
-               url := host+"/"+locator
+               url := host + "/" + locator
                req, err := http.NewRequest("GET", url, nil)
                if err != nil {
                        continue
@@ -148,8 +149,8 @@ func (kc *KeepClient) Get(locator string) (io.ReadCloser, int64, string, error)
                }
                return HashCheckingReader{
                        Reader: resp.Body,
-                       Hash: md5.New(),
-                       Check: locator[0:32],
+                       Hash:   md5.New(),
+                       Check:  locator[0:32],
                }, resp.ContentLength, url, nil
        }
        log.Printf("DEBUG: GET %s failed: %v", locator, errs)
@@ -165,7 +166,7 @@ func (kc *KeepClient) Get(locator string) (io.ReadCloser, int64, string, error)
 // and the URI reporting the data size.
 func (kc *KeepClient) Ask(locator string) (int64, string, error) {
        for _, host := range kc.getSortedRoots(locator) {
-               url := host+"/"+locator
+               url := host + "/" + locator
                req, err := http.NewRequest("HEAD", url, nil)
                if err != nil {
                        continue
@@ -194,6 +195,14 @@ func (kc *KeepClient) GatewayRoots() map[string]string {
        return *kc.gatewayRoots
 }
 
+// WritableLocalRoots() returns the map of writable local Keep services:
+// uuid -> baseURI.
+func (kc *KeepClient) WritableLocalRoots() map[string]string {
+       kc.lock.RLock()
+       defer kc.lock.RUnlock()
+       return *kc.writableLocalRoots
+}
+
 // SetServiceRoots updates the localRoots and gatewayRoots maps,
 // without risk of disrupting operations that are already in progress.
 //
@@ -201,18 +210,26 @@ func (kc *KeepClient) GatewayRoots() map[string]string {
 // caller can reuse/modify them after SetServiceRoots returns, but
 // they should not be modified by any other goroutine while
 // SetServiceRoots is running.
-func (kc *KeepClient) SetServiceRoots(newLocals, newGateways map[string]string) {
+func (kc *KeepClient) SetServiceRoots(newLocals, newWritableLocals map[string]string, newGateways map[string]string) {
        locals := make(map[string]string)
        for uuid, root := range newLocals {
                locals[uuid] = root
        }
+
+       writables := make(map[string]string)
+       for uuid, root := range newWritableLocals {
+               writables[uuid] = root
+       }
+
        gateways := make(map[string]string)
        for uuid, root := range newGateways {
                gateways[uuid] = root
        }
+
        kc.lock.Lock()
        defer kc.lock.Unlock()
        kc.localRoots = &locals
+       kc.writableLocalRoots = &writables
        kc.gatewayRoots = &gateways
 }
 
@@ -246,8 +263,8 @@ func (kc *KeepClient) getSortedRoots(locator string) []string {
 
 type Locator struct {
        Hash  string
-       Size  int               // -1 if data size is not known
-       Hints []string          // Including the size hint, if any
+       Size  int      // -1 if data size is not known
+       Hints []string // Including the size hint, if any
 }
 
 func (loc *Locator) String() string {