Browse code

IPAM watch removal and multistore support

Remove the need for watching for IPAM data
structures and add multi store support code and
data reorganization to simplify address space
management.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan authored on 2015/10/05 20:24:44
Showing 6 changed files
... ...
@@ -57,9 +57,6 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
57 57
 		return h, nil
58 58
 	}
59 59
 
60
-	// Register for status changes
61
-	h.watchForChanges()
62
-
63 60
 	// Get the initial status from the ds if present.
64 61
 	if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
65 62
 		return nil, err
... ...
@@ -252,6 +249,12 @@ func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32
252 252
 	)
253 253
 
254 254
 	for {
255
+		if h.store != nil {
256
+			if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
257
+				return ret, err
258
+			}
259
+		}
260
+
255 261
 		h.Lock()
256 262
 		// Get position if available
257 263
 		if release {
... ...
@@ -70,46 +70,47 @@ func (h *Handle) Exists() bool {
70 70
 	return h.dbExists
71 71
 }
72 72
 
73
+// New method returns a handle based on the receiver handle
74
+func (h *Handle) New() datastore.KVObject {
75
+	h.Lock()
76
+	defer h.Unlock()
77
+
78
+	return &Handle{
79
+		app:   h.app,
80
+		id:    h.id,
81
+		store: h.store,
82
+	}
83
+}
84
+
85
+// CopyTo deep copies the handle into the passed destination object
86
+func (h *Handle) CopyTo(o datastore.KVObject) error {
87
+	h.Lock()
88
+	defer h.Unlock()
89
+
90
+	dstH := o.(*Handle)
91
+	dstH.bits = h.bits
92
+	dstH.unselected = h.unselected
93
+	dstH.head = h.head.getCopy()
94
+	dstH.app = h.app
95
+	dstH.id = h.id
96
+	dstH.dbIndex = h.dbIndex
97
+	dstH.dbExists = h.dbExists
98
+	dstH.store = h.store
99
+
100
+	return nil
101
+}
102
+
73 103
 // Skip provides a way for a KV Object to avoid persisting it in the KV Store
74 104
 func (h *Handle) Skip() bool {
75 105
 	return false
76 106
 }
77 107
 
78 108
 // DataScope method returns the storage scope of the datastore
79
-func (h *Handle) DataScope() datastore.DataScope {
80
-	return datastore.GlobalScope
81
-}
82
-
83
-func (h *Handle) watchForChanges() error {
109
+func (h *Handle) DataScope() string {
84 110
 	h.Lock()
85
-	store := h.store
86
-	h.Unlock()
87
-
88
-	if store == nil {
89
-		return nil
90
-	}
111
+	defer h.Unlock()
91 112
 
92
-	kvpChan, err := store.KVStore().Watch(datastore.Key(h.Key()...), nil)
93
-	if err != nil {
94
-		return err
95
-	}
96
-	go func() {
97
-		for {
98
-			select {
99
-			case kvPair := <-kvpChan:
100
-				// Only process remote update
101
-				if kvPair != nil && (kvPair.LastIndex != h.Index()) {
102
-					err := h.fromDsValue(kvPair.Value)
103
-					if err != nil {
104
-						log.Warnf("Failed to reconstruct bitseq handle from ds watch: %s", err.Error())
105
-					} else {
106
-						h.SetIndex(kvPair.LastIndex)
107
-					}
108
-				}
109
-			}
110
-		}
111
-	}()
112
-	return nil
113
+	return h.store.Scope()
113 114
 }
114 115
 
115 116
 func (h *Handle) fromDsValue(value []byte) error {
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"sync"
7 7
 
8 8
 	log "github.com/Sirupsen/logrus"
9
-	"github.com/docker/libkv/store"
10 9
 	"github.com/docker/libnetwork/bitseq"
11 10
 	"github.com/docker/libnetwork/datastore"
12 11
 	"github.com/docker/libnetwork/ipamapi"
... ...
@@ -30,13 +29,10 @@ const (
30 30
 type Allocator struct {
31 31
 	// Predefined pools for default address spaces
32 32
 	predefined map[string][]*net.IPNet
33
-	// Static subnet information
34
-	localSubnets  *PoolsConfig
35
-	globalSubnets *PoolsConfig
33
+	addrSpaces map[string]*addrSpace
34
+	// stores        []datastore.Datastore
36 35
 	// Allocated addresses in each address space's subnet
37 36
 	addresses map[SubnetKey]*bitseq.Handle
38
-	// Datastore
39
-	addrSpace2Configs map[string]*PoolsConfig
40 37
 	sync.Mutex
41 38
 }
42 39
 
... ...
@@ -44,71 +40,84 @@ type Allocator struct {
44 44
 func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
45 45
 	a := &Allocator{}
46 46
 
47
-	a.localSubnets = &PoolsConfig{
48
-		subnets: map[SubnetKey]*PoolData{},
49
-		id:      dsConfigKey + "/Pools",
50
-		scope:   datastore.LocalScope,
51
-		ds:      lcDs,
52
-		alloc:   a,
53
-	}
54
-
55
-	a.globalSubnets = &PoolsConfig{
56
-		subnets: map[SubnetKey]*PoolData{},
57
-		id:      dsConfigKey + "/Pools",
58
-		scope:   datastore.GlobalScope,
59
-		ds:      glDs,
60
-		alloc:   a,
61
-	}
62
-
47
+	// Load predefined subnet pools
63 48
 	a.predefined = map[string][]*net.IPNet{
64 49
 		localAddressSpace:  initLocalPredefinedPools(),
65 50
 		globalAddressSpace: initGlobalPredefinedPools(),
66 51
 	}
67 52
 
68
-	a.addrSpace2Configs = map[string]*PoolsConfig{
69
-		localAddressSpace:  a.localSubnets,
70
-		globalAddressSpace: a.globalSubnets,
71
-	}
72
-
53
+	// Initialize bitseq map
73 54
 	a.addresses = make(map[SubnetKey]*bitseq.Handle)
74 55
 
75
-	cfgs := []struct {
76
-		cfg *PoolsConfig
77
-		dsc string
56
+	// Initialize address spaces
57
+	a.addrSpaces = make(map[string]*addrSpace)
58
+	for _, aspc := range []struct {
59
+		as string
60
+		ds datastore.DataStore
78 61
 	}{
79
-		{a.localSubnets, "local"},
80
-		{a.globalSubnets, "global"},
81
-	}
82
-	// Get the initial local/global pools configfrom the datastores
83
-	var inserterList []func() error
84
-	for _, e := range cfgs {
85
-		if e.cfg.ds == nil {
62
+		{localAddressSpace, lcDs},
63
+		{globalAddressSpace, glDs},
64
+	} {
65
+		if aspc.ds == nil {
86 66
 			continue
87 67
 		}
88
-		if err := e.cfg.watchForChanges(); err != nil {
89
-			log.Warnf("Error on registering watch for %s datastore: %v", e.dsc, err)
90
-		}
91
-		if err := e.cfg.readFromStore(); err != nil && err != store.ErrKeyNotFound {
92
-			return nil, fmt.Errorf("failed to retrieve the ipam %s pools config from datastore: %v", e.dsc, err)
68
+
69
+		a.addrSpaces[aspc.as] = &addrSpace{
70
+			subnets: map[SubnetKey]*PoolData{},
71
+			id:      dsConfigKey + "/" + aspc.as,
72
+			scope:   aspc.ds.Scope(),
73
+			ds:      aspc.ds,
74
+			alloc:   a,
93 75
 		}
94
-		e.cfg.Lock()
95
-		for k, v := range e.cfg.subnets {
96
-			if v.Range == nil {
97
-				inserterList = append(inserterList, func() error { return a.insertBitMask(e.cfg.ds, k, v.Pool) })
98
-			}
76
+	}
77
+
78
+	return a, nil
79
+}
80
+
81
+func (a *Allocator) refresh(as string) error {
82
+	aSpace, err := a.getAddressSpaceFromStore(as)
83
+	if err != nil {
84
+		return fmt.Errorf("error getting pools config from store during init: %v",
85
+			err)
86
+	}
87
+
88
+	if aSpace == nil {
89
+		return nil
90
+	}
91
+
92
+	if err := a.updateBitMasks(aSpace); err != nil {
93
+		return fmt.Errorf("error updating bit masks during init: %v", err)
94
+	}
95
+
96
+	a.Lock()
97
+	a.addrSpaces[as] = aSpace
98
+	a.Unlock()
99
+
100
+	return nil
101
+}
102
+
103
+func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
104
+	var inserterList []func() error
105
+
106
+	aSpace.Lock()
107
+	for k, v := range aSpace.subnets {
108
+		if v.Range == nil {
109
+			inserterList = append(inserterList,
110
+				func() error { return a.insertBitMask(k, v.Pool) })
99 111
 		}
100
-		e.cfg.Unlock()
101 112
 	}
113
+	aSpace.Unlock()
114
+
102 115
 	// Add the bitmasks (data could come from datastore)
103 116
 	if inserterList != nil {
104 117
 		for _, f := range inserterList {
105 118
 			if err := f(); err != nil {
106
-				return nil, err
119
+				return err
107 120
 			}
108 121
 		}
109 122
 	}
110 123
 
111
-	return a, nil
124
+	return nil
112 125
 }
113 126
 
114 127
 // GetDefaultAddressSpaces returns the local and global default address spaces
... ...
@@ -123,25 +132,29 @@ func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[
123 123
 		return "", nil, nil, ipamapi.ErrInvalidPool
124 124
 	}
125 125
 
126
-	cfg, err := a.getPoolsConfig(addressSpace)
126
+retry:
127
+	if err := a.refresh(addressSpace); err != nil {
128
+		return "", nil, nil, err
129
+	}
130
+
131
+	aSpace, err := a.getAddrSpace(addressSpace)
127 132
 	if err != nil {
128 133
 		return "", nil, nil, err
129 134
 	}
130 135
 
131
-retry:
132
-	insert, err := cfg.updatePoolDBOnAdd(*k, nw, ipr)
136
+	insert, err := aSpace.updatePoolDBOnAdd(*k, nw, ipr)
133 137
 	if err != nil {
134 138
 		return "", nil, nil, err
135 139
 	}
136
-	if err := cfg.writeToStore(); err != nil {
140
+
141
+	if err := a.writeToStore(aSpace); err != nil {
137 142
 		if _, ok := err.(types.RetryError); !ok {
138 143
 			return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
139 144
 		}
140
-		if erru := cfg.readFromStore(); erru != nil {
141
-			return "", nil, nil, fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
142
-		}
145
+
143 146
 		goto retry
144 147
 	}
148
+
145 149
 	return k.String(), aw, nil, insert()
146 150
 }
147 151
 
... ...
@@ -152,23 +165,25 @@ func (a *Allocator) ReleasePool(poolID string) error {
152 152
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)
153 153
 	}
154 154
 
155
-	cfg, err := a.getPoolsConfig(k.AddressSpace)
155
+retry:
156
+	if err := a.refresh(k.AddressSpace); err != nil {
157
+		return err
158
+	}
159
+
160
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
156 161
 	if err != nil {
157 162
 		return err
158 163
 	}
159 164
 
160
-retry:
161
-	remove, err := cfg.updatePoolDBOnRemoval(k)
165
+	remove, err := aSpace.updatePoolDBOnRemoval(k)
162 166
 	if err != nil {
163 167
 		return err
164 168
 	}
165
-	if err = cfg.writeToStore(); err != nil {
169
+
170
+	if err = a.writeToStore(aSpace); err != nil {
166 171
 		if _, ok := err.(types.RetryError); !ok {
167 172
 			return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
168 173
 		}
169
-		if erru := cfg.readFromStore(); erru != nil {
170
-			return fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
171
-		}
172 174
 		goto retry
173 175
 	}
174 176
 
... ...
@@ -177,14 +192,14 @@ retry:
177 177
 
178 178
 // Given the address space, returns the local or global PoolConfig based on the
179 179
 // address space is local or global. AddressSpace locality is being registered with IPAM out of band.
180
-func (a *Allocator) getPoolsConfig(addrSpace string) (*PoolsConfig, error) {
180
+func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) {
181 181
 	a.Lock()
182 182
 	defer a.Unlock()
183
-	cfg, ok := a.addrSpace2Configs[addrSpace]
183
+	aSpace, ok := a.addrSpaces[as]
184 184
 	if !ok {
185
-		return nil, types.BadRequestErrorf("cannot find locality of address space: %s", addrSpace)
185
+		return nil, types.BadRequestErrorf("cannot find locality of address space: %s", as)
186 186
 	}
187
-	return cfg, nil
187
+	return aSpace, nil
188 188
 }
189 189
 
190 190
 func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *net.IPNet, *AddressRange, error) {
... ...
@@ -224,8 +239,14 @@ func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool
224 224
 	return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, aw, ipr, nil
225 225
 }
226 226
 
227
-func (a *Allocator) insertBitMask(store datastore.DataStore, key SubnetKey, pool *net.IPNet) error {
227
+func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
228 228
 	log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
229
+
230
+	store := a.getStore(key.AddressSpace)
231
+	if store == nil {
232
+		return fmt.Errorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
233
+	}
234
+
229 235
 	ipVer := getAddressVersion(pool.IP)
230 236
 	ones, bits := pool.Mask.Size()
231 237
 	numAddresses := uint32(1 << uint(bits-ones))
... ...
@@ -252,13 +273,13 @@ func (a *Allocator) insertBitMask(store datastore.DataStore, key SubnetKey, pool
252 252
 	return nil
253 253
 }
254 254
 
255
-func (a *Allocator) retrieveBitmask(ds datastore.DataStore, k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
255
+func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
256 256
 	a.Lock()
257 257
 	bm, ok := a.addresses[k]
258 258
 	a.Unlock()
259 259
 	if !ok {
260 260
 		log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
261
-		if err := a.insertBitMask(ds, k, n); err != nil {
261
+		if err := a.insertBitMask(k, n); err != nil {
262 262
 			return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
263 263
 		}
264 264
 		a.Lock()
... ...
@@ -289,7 +310,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
289 289
 		return nil, fmt.Errorf("no default pool availbale for non-default addresss spaces")
290 290
 	}
291 291
 
292
-	cfg, err := a.getPoolsConfig(as)
292
+	aSpace, err := a.getAddrSpace(as)
293 293
 	if err != nil {
294 294
 		return nil, err
295 295
 	}
... ...
@@ -298,14 +319,14 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
298 298
 		if v != getAddressVersion(nw.IP) {
299 299
 			continue
300 300
 		}
301
-		cfg.Lock()
302
-		_, ok := cfg.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
303
-		cfg.Unlock()
301
+		aSpace.Lock()
302
+		_, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
303
+		aSpace.Unlock()
304 304
 		if ok {
305 305
 			continue
306 306
 		}
307 307
 
308
-		if !cfg.contains(as, nw) {
308
+		if !aSpace.contains(as, nw) {
309 309
 			if as == localAddressSpace {
310 310
 				if err := netutils.CheckRouteOverlaps(nw); err == nil {
311 311
 					return nw, nil
... ...
@@ -326,31 +347,35 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
326 326
 		return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
327 327
 	}
328 328
 
329
-	cfg, err := a.getPoolsConfig(k.AddressSpace)
329
+	if err := a.refresh(k.AddressSpace); err != nil {
330
+		return nil, nil, err
331
+	}
332
+
333
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
330 334
 	if err != nil {
331 335
 		return nil, nil, err
332 336
 	}
333 337
 
334
-	cfg.Lock()
335
-	p, ok := cfg.subnets[k]
338
+	aSpace.Lock()
339
+	p, ok := aSpace.subnets[k]
336 340
 	if !ok {
337
-		cfg.Unlock()
341
+		aSpace.Unlock()
338 342
 		return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
339 343
 	}
340 344
 
341 345
 	if prefAddress != nil && !p.Pool.Contains(prefAddress) {
342
-		cfg.Unlock()
346
+		aSpace.Unlock()
343 347
 		return nil, nil, ipamapi.ErrIPOutOfRange
344 348
 	}
345 349
 
346 350
 	c := p
347 351
 	for c.Range != nil {
348 352
 		k = c.ParentKey
349
-		c, ok = cfg.subnets[k]
353
+		c, ok = aSpace.subnets[k]
350 354
 	}
351
-	cfg.Unlock()
355
+	aSpace.Unlock()
352 356
 
353
-	bm, err := a.retrieveBitmask(cfg.ds, k, c.Pool)
357
+	bm, err := a.retrieveBitmask(k, c.Pool)
354 358
 	if err != nil {
355 359
 		return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
356 360
 			k.String(), prefAddress, poolID, err)
... ...
@@ -370,29 +395,33 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
370 370
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)
371 371
 	}
372 372
 
373
-	cfg, err := a.getPoolsConfig(k.AddressSpace)
373
+	if err := a.refresh(k.AddressSpace); err != nil {
374
+		return err
375
+	}
376
+
377
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
374 378
 	if err != nil {
375 379
 		return err
376 380
 	}
377 381
 
378
-	cfg.Lock()
379
-	p, ok := cfg.subnets[k]
382
+	aSpace.Lock()
383
+	p, ok := aSpace.subnets[k]
380 384
 	if !ok {
381
-		cfg.Unlock()
385
+		aSpace.Unlock()
382 386
 		return ipamapi.ErrBadPool
383 387
 	}
384 388
 
385 389
 	if address == nil || !p.Pool.Contains(address) {
386
-		cfg.Unlock()
390
+		aSpace.Unlock()
387 391
 		return ipamapi.ErrInvalidRequest
388 392
 	}
389 393
 
390 394
 	c := p
391 395
 	for c.Range != nil {
392 396
 		k = c.ParentKey
393
-		c = cfg.subnets[k]
397
+		c = aSpace.subnets[k]
394 398
 	}
395
-	cfg.Unlock()
399
+	aSpace.Unlock()
396 400
 
397 401
 	mask := p.Pool.Mask
398 402
 	if p.Range != nil {
... ...
@@ -403,7 +432,7 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
403 403
 		return fmt.Errorf("failed to release address %s: %v", address.String(), err)
404 404
 	}
405 405
 
406
-	bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool)
406
+	bm, err := a.retrieveBitmask(k, c.Pool)
407 407
 	if err != nil {
408 408
 		return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
409 409
 			k.String(), address, poolID, err)
... ...
@@ -449,23 +478,20 @@ func (a *Allocator) DumpDatabase() string {
449 449
 	a.Lock()
450 450
 	defer a.Unlock()
451 451
 
452
-	s := fmt.Sprintf("\n\nLocal Pool Config")
453
-	a.localSubnets.Lock()
454
-	for k, config := range a.localSubnets.subnets {
455
-		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
456
-	}
457
-	a.localSubnets.Unlock()
458
-
459
-	s = fmt.Sprintf("%s\n\nGlobal Pool Config", s)
460
-	a.globalSubnets.Lock()
461
-	for k, config := range a.globalSubnets.subnets {
462
-		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
452
+	var s string
453
+	for as, aSpace := range a.addrSpaces {
454
+		s = fmt.Sprintf("\n\n%s Config", as)
455
+		aSpace.Lock()
456
+		for k, config := range aSpace.subnets {
457
+			s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
458
+		}
459
+		aSpace.Unlock()
463 460
 	}
464
-	a.globalSubnets.Unlock()
465 461
 
466 462
 	s = fmt.Sprintf("%s\n\nBitmasks", s)
467 463
 	for k, bm := range a.addresses {
468 464
 		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
469 465
 	}
466
+
470 467
 	return s
471 468
 }
... ...
@@ -11,7 +11,6 @@ import (
11 11
 
12 12
 	"github.com/docker/libkv/store"
13 13
 	"github.com/docker/libnetwork/bitseq"
14
-	"github.com/docker/libnetwork/config"
15 14
 	"github.com/docker/libnetwork/datastore"
16 15
 	"github.com/docker/libnetwork/ipamapi"
17 16
 	"github.com/docker/libnetwork/netutils"
... ...
@@ -32,9 +31,9 @@ func randomLocalStore() (datastore.DataStore, error) {
32 32
 	if err := tmp.Close(); err != nil {
33 33
 		return nil, fmt.Errorf("Error closing temp file: %v", err)
34 34
 	}
35
-	return datastore.NewDataStore(&config.DatastoreCfg{
35
+	return datastore.NewDataStore(datastore.LocalScope, &datastore.ScopeCfg{
36 36
 		Embedded: true,
37
-		Client: config.DatastoreClientCfg{
37
+		Client: datastore.ScopeClientCfg{
38 38
 			Provider: "boltdb",
39 39
 			Address:  defaultPrefix + tmp.Name(),
40 40
 			Config: &store.Config{
... ...
@@ -191,7 +190,11 @@ func TestSubnetsMarshal(t *testing.T) {
191 191
 		t.Fatal(err)
192 192
 	}
193 193
 
194
-	cfg := a.localSubnets
194
+	cfg, err := a.getAddrSpace(localAddressSpace)
195
+	if err != nil {
196
+		t.Fatal(err)
197
+	}
198
+
195 199
 	ba := cfg.Value()
196 200
 	if err := cfg.SetValue(ba); err != nil {
197 201
 		t.Fatal(err)
... ...
@@ -221,7 +224,7 @@ func TestAddSubnets(t *testing.T) {
221 221
 	if err != nil {
222 222
 		t.Fatal(err)
223 223
 	}
224
-	a.addrSpace2Configs["abc"] = a.addrSpace2Configs[localAddressSpace]
224
+	a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace]
225 225
 
226 226
 	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
227 227
 	if err != nil {
... ...
@@ -290,7 +293,13 @@ func TestAddReleasePoolID(t *testing.T) {
290 290
 	if err != nil {
291 291
 		t.Fatal(err)
292 292
 	}
293
-	subnets := a.localSubnets.subnets
293
+
294
+	aSpace, err := a.getAddrSpace(localAddressSpace)
295
+	if err != nil {
296
+		t.Fatal(err)
297
+	}
298
+
299
+	subnets := aSpace.subnets
294 300
 	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
295 301
 	if err != nil {
296 302
 		t.Fatalf("Unexpected failure in adding pool")
... ...
@@ -298,6 +307,14 @@ func TestAddReleasePoolID(t *testing.T) {
298 298
 	if err := k0.FromString(pid0); err != nil {
299 299
 		t.Fatal(err)
300 300
 	}
301
+
302
+	aSpace, err = a.getAddrSpace(localAddressSpace)
303
+	if err != nil {
304
+		t.Fatal(err)
305
+	}
306
+
307
+	subnets = aSpace.subnets
308
+
301 309
 	if subnets[k0].RefCount != 1 {
302 310
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
303 311
 	}
... ...
@@ -309,6 +326,13 @@ func TestAddReleasePoolID(t *testing.T) {
309 309
 	if err := k1.FromString(pid1); err != nil {
310 310
 		t.Fatal(err)
311 311
 	}
312
+
313
+	aSpace, err = a.getAddrSpace(localAddressSpace)
314
+	if err != nil {
315
+		t.Fatal(err)
316
+	}
317
+
318
+	subnets = aSpace.subnets
312 319
 	if subnets[k1].RefCount != 1 {
313 320
 		t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount)
314 321
 	}
... ...
@@ -323,6 +347,13 @@ func TestAddReleasePoolID(t *testing.T) {
323 323
 	if err := k2.FromString(pid2); err != nil {
324 324
 		t.Fatal(err)
325 325
 	}
326
+
327
+	aSpace, err = a.getAddrSpace(localAddressSpace)
328
+	if err != nil {
329
+		t.Fatal(err)
330
+	}
331
+
332
+	subnets = aSpace.subnets
326 333
 	if subnets[k2].RefCount != 2 {
327 334
 		t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount)
328 335
 	}
... ...
@@ -334,12 +365,26 @@ func TestAddReleasePoolID(t *testing.T) {
334 334
 	if err := a.ReleasePool(pid1); err != nil {
335 335
 		t.Fatal(err)
336 336
 	}
337
+
338
+	aSpace, err = a.getAddrSpace(localAddressSpace)
339
+	if err != nil {
340
+		t.Fatal(err)
341
+	}
342
+
343
+	subnets = aSpace.subnets
337 344
 	if subnets[k0].RefCount != 2 {
338 345
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
339 346
 	}
340 347
 	if err := a.ReleasePool(pid0); err != nil {
341 348
 		t.Fatal(err)
342 349
 	}
350
+
351
+	aSpace, err = a.getAddrSpace(localAddressSpace)
352
+	if err != nil {
353
+		t.Fatal(err)
354
+	}
355
+
356
+	subnets = aSpace.subnets
343 357
 	if subnets[k0].RefCount != 1 {
344 358
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
345 359
 	}
... ...
@@ -351,6 +396,13 @@ func TestAddReleasePoolID(t *testing.T) {
351 351
 	if pid00 != pid0 {
352 352
 		t.Fatalf("main pool should still exist")
353 353
 	}
354
+
355
+	aSpace, err = a.getAddrSpace(localAddressSpace)
356
+	if err != nil {
357
+		t.Fatal(err)
358
+	}
359
+
360
+	subnets = aSpace.subnets
354 361
 	if subnets[k0].RefCount != 2 {
355 362
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
356 363
 	}
... ...
@@ -358,6 +410,13 @@ func TestAddReleasePoolID(t *testing.T) {
358 358
 	if err := a.ReleasePool(pid2); err != nil {
359 359
 		t.Fatal(err)
360 360
 	}
361
+
362
+	aSpace, err = a.getAddrSpace(localAddressSpace)
363
+	if err != nil {
364
+		t.Fatal(err)
365
+	}
366
+
367
+	subnets = aSpace.subnets
361 368
 	if subnets[k0].RefCount != 1 {
362 369
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
363 370
 	}
... ...
@@ -365,6 +424,13 @@ func TestAddReleasePoolID(t *testing.T) {
365 365
 	if err := a.ReleasePool(pid00); err != nil {
366 366
 		t.Fatal(err)
367 367
 	}
368
+
369
+	aSpace, err = a.getAddrSpace(localAddressSpace)
370
+	if err != nil {
371
+		t.Fatal(err)
372
+	}
373
+
374
+	subnets = aSpace.subnets
368 375
 	if bp, ok := subnets[k0]; ok {
369 376
 		t.Fatalf("Base pool %s is still present: %v", k0, bp)
370 377
 	}
... ...
@@ -373,6 +439,13 @@ func TestAddReleasePoolID(t *testing.T) {
373 373
 	if err != nil {
374 374
 		t.Fatalf("Unexpected failure in adding pool")
375 375
 	}
376
+
377
+	aSpace, err = a.getAddrSpace(localAddressSpace)
378
+	if err != nil {
379
+		t.Fatal(err)
380
+	}
381
+
382
+	subnets = aSpace.subnets
376 383
 	if subnets[k0].RefCount != 1 {
377 384
 		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
378 385
 	}
... ...
@@ -417,18 +490,6 @@ func TestPredefinedPool(t *testing.T) {
417 417
 	if nw != a.predefined[localAddressSpace][i] {
418 418
 		t.Fatalf("Unexpected default network returned: %s", nw)
419 419
 	}
420
-
421
-	i, available, err = getFirstAvailablePool(a, globalAddressSpace, 2)
422
-	if err != nil {
423
-		t.Skip(err)
424
-	}
425
-	nw, err = a.getPredefinedPool(globalAddressSpace, false)
426
-	if err != nil {
427
-		t.Fatal(err)
428
-	}
429
-	if nw != available {
430
-		t.Fatalf("Unexpected default network returned: %s", nw)
431
-	}
432 420
 }
433 421
 
434 422
 func getFirstAvailablePool(a *Allocator, as string, atLeast int) (int, *net.IPNet, error) {
... ...
@@ -475,7 +536,13 @@ func TestRemoveSubnet(t *testing.T) {
475 475
 	if err != nil {
476 476
 		t.Fatal(err)
477 477
 	}
478
-	a.addrSpace2Configs["splane"] = a.addrSpace2Configs[localAddressSpace]
478
+	a.addrSpaces["splane"] = &addrSpace{
479
+		id:      dsConfigKey + "/" + "splane",
480
+		ds:      a.addrSpaces[localAddressSpace].ds,
481
+		alloc:   a.addrSpaces[localAddressSpace].alloc,
482
+		scope:   a.addrSpaces[localAddressSpace].scope,
483
+		subnets: map[SubnetKey]*PoolData{},
484
+	}
479 485
 
480 486
 	input := []struct {
481 487
 		addrSpace string
... ...
@@ -512,7 +579,13 @@ func TestGetSameAddress(t *testing.T) {
512 512
 	if err != nil {
513 513
 		t.Fatal(err)
514 514
 	}
515
-	a.addrSpace2Configs["giallo"] = a.addrSpace2Configs[localAddressSpace]
515
+	a.addrSpaces["giallo"] = &addrSpace{
516
+		id:      dsConfigKey + "/" + "giallo",
517
+		ds:      a.addrSpaces[localAddressSpace].ds,
518
+		alloc:   a.addrSpaces[localAddressSpace].alloc,
519
+		scope:   a.addrSpaces[localAddressSpace].scope,
520
+		subnets: map[SubnetKey]*PoolData{},
521
+	}
516 522
 
517 523
 	pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false)
518 524
 	if err != nil {
... ...
@@ -536,7 +609,13 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
536 536
 	if err != nil {
537 537
 		t.Fatal(err)
538 538
 	}
539
-	a.addrSpace2Configs["rosso"] = a.addrSpace2Configs[localAddressSpace]
539
+	a.addrSpaces["rosso"] = &addrSpace{
540
+		id:      dsConfigKey + "/" + "rosso",
541
+		ds:      a.addrSpaces[localAddressSpace].ds,
542
+		alloc:   a.addrSpaces[localAddressSpace].alloc,
543
+		scope:   a.addrSpaces[localAddressSpace].scope,
544
+		subnets: map[SubnetKey]*PoolData{},
545
+	}
540 546
 
541 547
 	poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
542 548
 	if err != nil {
... ...
@@ -615,17 +694,23 @@ func TestGetAddress(t *testing.T) {
615 615
 
616 616
 func TestRequestSyntaxCheck(t *testing.T) {
617 617
 	var (
618
-		pool      = "192.168.0.0/16"
619
-		subPool   = "192.168.0.0/24"
620
-		addrSpace = "green"
621
-		err       error
618
+		pool    = "192.168.0.0/16"
619
+		subPool = "192.168.0.0/24"
620
+		as      = "green"
621
+		err     error
622 622
 	)
623 623
 
624 624
 	a, err := getAllocator()
625 625
 	if err != nil {
626 626
 		t.Fatal(err)
627 627
 	}
628
-	a.addrSpace2Configs[addrSpace] = a.addrSpace2Configs[localAddressSpace]
628
+	a.addrSpaces[as] = &addrSpace{
629
+		id:      dsConfigKey + "/" + as,
630
+		ds:      a.addrSpaces[localAddressSpace].ds,
631
+		alloc:   a.addrSpaces[localAddressSpace].alloc,
632
+		scope:   a.addrSpaces[localAddressSpace].scope,
633
+		subnets: map[SubnetKey]*PoolData{},
634
+	}
629 635
 
630 636
 	_, _, _, err = a.RequestPool("", pool, "", nil, false)
631 637
 	if err == nil {
... ...
@@ -637,12 +722,12 @@ func TestRequestSyntaxCheck(t *testing.T) {
637 637
 		t.Fatalf("Failed to detect wrong request: empty address space")
638 638
 	}
639 639
 
640
-	_, _, _, err = a.RequestPool(addrSpace, "", subPool, nil, false)
640
+	_, _, _, err = a.RequestPool(as, "", subPool, nil, false)
641 641
 	if err == nil {
642 642
 		t.Fatalf("Failed to detect wrong request: subPool specified and no pool")
643 643
 	}
644 644
 
645
-	pid, _, _, err := a.RequestPool(addrSpace, pool, subPool, nil, false)
645
+	pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false)
646 646
 	if err != nil {
647 647
 		t.Fatalf("Unexpected failure: %v", err)
648 648
 	}
... ...
@@ -764,6 +849,7 @@ func TestRelease(t *testing.T) {
764 764
 	for i, inp := range toRelease {
765 765
 		ip0 := net.ParseIP(inp.address)
766 766
 		a.ReleaseAddress(pid, ip0)
767
+		bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
767 768
 		if bm.Unselected() != 1 {
768 769
 			t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected())
769 770
 		}
... ...
@@ -2,30 +2,30 @@ package ipam
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
+	"fmt"
5 6
 
6 7
 	log "github.com/Sirupsen/logrus"
7
-	"github.com/docker/libkv/store"
8 8
 	"github.com/docker/libnetwork/datastore"
9 9
 	"github.com/docker/libnetwork/types"
10 10
 )
11 11
 
12 12
 // Key provides the Key to be used in KV Store
13
-func (cfg *PoolsConfig) Key() []string {
14
-	cfg.Lock()
15
-	defer cfg.Unlock()
16
-	return []string{cfg.id}
13
+func (aSpace *addrSpace) Key() []string {
14
+	aSpace.Lock()
15
+	defer aSpace.Unlock()
16
+	return []string{aSpace.id}
17 17
 }
18 18
 
19 19
 // KeyPrefix returns the immediate parent key that can be used for tree walk
20
-func (cfg *PoolsConfig) KeyPrefix() []string {
21
-	cfg.Lock()
22
-	defer cfg.Unlock()
20
+func (aSpace *addrSpace) KeyPrefix() []string {
21
+	aSpace.Lock()
22
+	defer aSpace.Unlock()
23 23
 	return []string{dsConfigKey}
24 24
 }
25 25
 
26 26
 // Value marshals the data to be stored in the KV store
27
-func (cfg *PoolsConfig) Value() []byte {
28
-	b, err := json.Marshal(cfg)
27
+func (aSpace *addrSpace) Value() []byte {
28
+	b, err := json.Marshal(aSpace)
29 29
 	if err != nil {
30 30
 		log.Warnf("Failed to marshal ipam configured pools: %v", err)
31 31
 		return nil
... ...
@@ -34,97 +34,94 @@ func (cfg *PoolsConfig) Value() []byte {
34 34
 }
35 35
 
36 36
 // SetValue unmarshalls the data from the KV store.
37
-func (cfg *PoolsConfig) SetValue(value []byte) error {
38
-	rc := &PoolsConfig{subnets: make(map[SubnetKey]*PoolData)}
37
+func (aSpace *addrSpace) SetValue(value []byte) error {
38
+	rc := &addrSpace{subnets: make(map[SubnetKey]*PoolData)}
39 39
 	if err := json.Unmarshal(value, rc); err != nil {
40 40
 		return err
41 41
 	}
42
-	cfg.subnets = rc.subnets
42
+	aSpace.subnets = rc.subnets
43 43
 	return nil
44 44
 }
45 45
 
46 46
 // Index returns the latest DB Index as seen by this object
47
-func (cfg *PoolsConfig) Index() uint64 {
48
-	cfg.Lock()
49
-	defer cfg.Unlock()
50
-	return cfg.dbIndex
47
+func (aSpace *addrSpace) Index() uint64 {
48
+	aSpace.Lock()
49
+	defer aSpace.Unlock()
50
+	return aSpace.dbIndex
51 51
 }
52 52
 
53 53
 // SetIndex method allows the datastore to store the latest DB Index into this object
54
-func (cfg *PoolsConfig) SetIndex(index uint64) {
55
-	cfg.Lock()
56
-	cfg.dbIndex = index
57
-	cfg.dbExists = true
58
-	cfg.Unlock()
54
+func (aSpace *addrSpace) SetIndex(index uint64) {
55
+	aSpace.Lock()
56
+	aSpace.dbIndex = index
57
+	aSpace.dbExists = true
58
+	aSpace.Unlock()
59 59
 }
60 60
 
61 61
 // Exists method is true if this object has been stored in the DB.
62
-func (cfg *PoolsConfig) Exists() bool {
63
-	cfg.Lock()
64
-	defer cfg.Unlock()
65
-	return cfg.dbExists
62
+func (aSpace *addrSpace) Exists() bool {
63
+	aSpace.Lock()
64
+	defer aSpace.Unlock()
65
+	return aSpace.dbExists
66 66
 }
67 67
 
68 68
 // Skip provides a way for a KV Object to avoid persisting it in the KV Store
69
-func (cfg *PoolsConfig) Skip() bool {
69
+func (aSpace *addrSpace) Skip() bool {
70 70
 	return false
71 71
 }
72 72
 
73
-func (cfg *PoolsConfig) watchForChanges() error {
74
-	if cfg.ds == nil {
75
-		return nil
76
-	}
77
-	kvpChan, err := cfg.ds.KVStore().Watch(datastore.Key(cfg.Key()...), nil)
78
-	if err != nil {
79
-		return err
73
+func (a *Allocator) getStore(as string) datastore.DataStore {
74
+	a.Lock()
75
+	defer a.Unlock()
76
+
77
+	return a.addrSpaces[as].ds
78
+}
79
+
80
+func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
81
+	store := a.getStore(as)
82
+	if store == nil {
83
+		return nil, fmt.Errorf("store for address space %s not found", as)
80 84
 	}
81
-	go func() {
82
-		for {
83
-			select {
84
-			case kvPair := <-kvpChan:
85
-				if kvPair != nil {
86
-					cfg.readFromKey(kvPair)
87
-				}
88
-			}
85
+
86
+	pc := &addrSpace{id: dsConfigKey + "/" + as, ds: store, alloc: a}
87
+	if err := store.GetObject(datastore.Key(pc.Key()...), pc); err != nil {
88
+		if err == datastore.ErrKeyNotFound {
89
+			return nil, nil
89 90
 		}
90
-	}()
91
-	return nil
91
+
92
+		return nil, fmt.Errorf("could not get pools config from store: %v", err)
93
+	}
94
+
95
+	return pc, nil
92 96
 }
93 97
 
94
-func (cfg *PoolsConfig) writeToStore() error {
95
-	if cfg.ds == nil {
96
-		return nil
98
+func (a *Allocator) writeToStore(aSpace *addrSpace) error {
99
+	store := aSpace.store()
100
+	if store == nil {
101
+		return fmt.Errorf("invalid store while trying to write %s address space", aSpace.DataScope())
97 102
 	}
98
-	err := cfg.ds.PutObjectAtomic(cfg)
103
+
104
+	err := store.PutObjectAtomic(aSpace)
99 105
 	if err == datastore.ErrKeyModified {
100 106
 		return types.RetryErrorf("failed to perform atomic write (%v). retry might fix the error", err)
101 107
 	}
102
-	return err
103
-}
104 108
 
105
-func (cfg *PoolsConfig) readFromStore() error {
106
-	if cfg.ds == nil {
107
-		return nil
108
-	}
109
-	return cfg.ds.GetObject(datastore.Key(cfg.Key()...), cfg)
109
+	return err
110 110
 }
111 111
 
112
-func (cfg *PoolsConfig) readFromKey(kvPair *store.KVPair) {
113
-	if cfg.dbIndex < kvPair.LastIndex {
114
-		cfg.SetValue(kvPair.Value)
115
-		cfg.dbIndex = kvPair.LastIndex
116
-		cfg.dbExists = true
112
+func (a *Allocator) deleteFromStore(aSpace *addrSpace) error {
113
+	store := aSpace.store()
114
+	if store == nil {
115
+		return fmt.Errorf("invalid store while trying to delete %s address space", aSpace.DataScope())
117 116
 	}
118
-}
119 117
 
120
-func (cfg *PoolsConfig) deleteFromStore() error {
121
-	if cfg.ds == nil {
122
-		return nil
123
-	}
124
-	return cfg.ds.DeleteObjectAtomic(cfg)
118
+	return store.DeleteObjectAtomic(aSpace)
125 119
 }
126 120
 
127 121
 // DataScope method returns the storage scope of the datastore
128
-func (cfg *PoolsConfig) DataScope() datastore.DataScope {
129
-	return cfg.scope
122
+func (aSpace *addrSpace) DataScope() string {
123
+	aSpace.Lock()
124
+	defer aSpace.Unlock()
125
+
126
+	return aSpace.scope
130 127
 }
... ...
@@ -27,13 +27,13 @@ type PoolData struct {
27 27
 	RefCount  int
28 28
 }
29 29
 
30
-// PoolsConfig contains the pool configurations
31
-type PoolsConfig struct {
30
+// addrSpace contains the pool configurations for the address space
31
+type addrSpace struct {
32 32
 	subnets  map[SubnetKey]*PoolData
33 33
 	dbIndex  uint64
34 34
 	dbExists bool
35 35
 	id       string
36
-	scope    datastore.DataScope
36
+	scope    string
37 37
 	ds       datastore.DataStore
38 38
 	alloc    *Allocator
39 39
 	sync.Mutex
... ...
@@ -153,18 +153,18 @@ func (p *PoolData) UnmarshalJSON(data []byte) error {
153 153
 	return nil
154 154
 }
155 155
 
156
-// MarshalJSON returns the JSON encoding of the PoolsConfig object
157
-func (cfg *PoolsConfig) MarshalJSON() ([]byte, error) {
158
-	cfg.Lock()
159
-	defer cfg.Unlock()
156
+// MarshalJSON returns the JSON encoding of the addrSpace object
157
+func (aSpace *addrSpace) MarshalJSON() ([]byte, error) {
158
+	aSpace.Lock()
159
+	defer aSpace.Unlock()
160 160
 
161 161
 	m := map[string]interface{}{
162
-		"Scope": string(cfg.scope),
162
+		"Scope": string(aSpace.scope),
163 163
 	}
164 164
 
165
-	if cfg.subnets != nil {
165
+	if aSpace.subnets != nil {
166 166
 		s := map[string]*PoolData{}
167
-		for k, v := range cfg.subnets {
167
+		for k, v := range aSpace.subnets {
168 168
 			s[k.String()] = v
169 169
 		}
170 170
 		m["Subnets"] = s
... ...
@@ -173,10 +173,10 @@ func (cfg *PoolsConfig) MarshalJSON() ([]byte, error) {
173 173
 	return json.Marshal(m)
174 174
 }
175 175
 
176
-// UnmarshalJSON decodes data into the PoolsConfig object
177
-func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
178
-	cfg.Lock()
179
-	defer cfg.Unlock()
176
+// UnmarshalJSON decodes data into the addrSpace object
177
+func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
178
+	aSpace.Lock()
179
+	defer aSpace.Unlock()
180 180
 
181 181
 	m := map[string]interface{}{}
182 182
 	err := json.Unmarshal(data, &m)
... ...
@@ -184,10 +184,10 @@ func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
184 184
 		return err
185 185
 	}
186 186
 
187
-	cfg.scope = datastore.LocalScope
187
+	aSpace.scope = datastore.LocalScope
188 188
 	s := m["Scope"].(string)
189 189
 	if s == string(datastore.GlobalScope) {
190
-		cfg.scope = datastore.GlobalScope
190
+		aSpace.scope = datastore.GlobalScope
191 191
 	}
192 192
 
193 193
 	if v, ok := m["Subnets"]; ok {
... ...
@@ -200,31 +200,81 @@ func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
200 200
 		for ks, v := range s {
201 201
 			k := SubnetKey{}
202 202
 			k.FromString(ks)
203
-			cfg.subnets[k] = v
203
+			aSpace.subnets[k] = v
204 204
 		}
205 205
 	}
206 206
 
207 207
 	return nil
208 208
 }
209 209
 
210
-func (cfg *PoolsConfig) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
211
-	cfg.Lock()
212
-	defer cfg.Unlock()
210
+// CopyTo deep copies the pool data to the destination pooldata
211
+func (p *PoolData) CopyTo(dstP *PoolData) error {
212
+	dstP.ParentKey = p.ParentKey
213
+	dstP.Pool = types.GetIPNetCopy(p.Pool)
214
+
215
+	if p.Range != nil {
216
+		dstP.Range = &AddressRange{}
217
+		dstP.Range.Sub = types.GetIPNetCopy(p.Range.Sub)
218
+		dstP.Range.Start = p.Range.Start
219
+		dstP.Range.End = p.Range.End
220
+	}
221
+
222
+	dstP.RefCount = p.RefCount
223
+	return nil
224
+}
225
+
226
+func (aSpace *addrSpace) CopyTo(o datastore.KVObject) error {
227
+	aSpace.Lock()
228
+	defer aSpace.Unlock()
229
+
230
+	dstAspace := o.(*addrSpace)
231
+
232
+	dstAspace.id = aSpace.id
233
+	dstAspace.ds = aSpace.ds
234
+	dstAspace.alloc = aSpace.alloc
235
+	dstAspace.scope = aSpace.scope
236
+	dstAspace.dbIndex = aSpace.dbIndex
237
+	dstAspace.dbExists = aSpace.dbExists
238
+
239
+	dstAspace.subnets = make(map[SubnetKey]*PoolData)
240
+	for k, v := range aSpace.subnets {
241
+		dstAspace.subnets[k] = &PoolData{}
242
+		v.CopyTo(dstAspace.subnets[k])
243
+	}
244
+
245
+	return nil
246
+}
247
+
248
+func (aSpace *addrSpace) New() datastore.KVObject {
249
+	aSpace.Lock()
250
+	defer aSpace.Unlock()
251
+
252
+	return &addrSpace{
253
+		id:    aSpace.id,
254
+		ds:    aSpace.ds,
255
+		alloc: aSpace.alloc,
256
+		scope: aSpace.scope,
257
+	}
258
+}
259
+
260
+func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
261
+	aSpace.Lock()
262
+	defer aSpace.Unlock()
213 263
 
214 264
 	// Check if already allocated
215
-	if p, ok := cfg.subnets[k]; ok {
216
-		cfg.incRefCount(p, 1)
265
+	if p, ok := aSpace.subnets[k]; ok {
266
+		aSpace.incRefCount(p, 1)
217 267
 		return func() error { return nil }, nil
218 268
 	}
219 269
 
220 270
 	// If master pool, check for overlap
221 271
 	if ipr == nil {
222
-		if cfg.contains(k.AddressSpace, nw) {
272
+		if aSpace.contains(k.AddressSpace, nw) {
223 273
 			return nil, ipamapi.ErrPoolOverlap
224 274
 		}
225 275
 		// This is a new master pool, add it along with corresponding bitmask
226
-		cfg.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
227
-		return func() error { return cfg.alloc.insertBitMask(cfg.ds, k, nw) }, nil
276
+		aSpace.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
277
+		return func() error { return aSpace.alloc.insertBitMask(k, nw) }, nil
228 278
 	}
229 279
 
230 280
 	// This is a new non-master pool
... ...
@@ -234,38 +284,38 @@ func (cfg *PoolsConfig) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *Addre
234 234
 		Range:     ipr,
235 235
 		RefCount:  1,
236 236
 	}
237
-	cfg.subnets[k] = p
237
+	aSpace.subnets[k] = p
238 238
 
239 239
 	// Look for parent pool
240
-	pp, ok := cfg.subnets[p.ParentKey]
240
+	pp, ok := aSpace.subnets[p.ParentKey]
241 241
 	if ok {
242
-		cfg.incRefCount(pp, 1)
242
+		aSpace.incRefCount(pp, 1)
243 243
 		return func() error { return nil }, nil
244 244
 	}
245 245
 
246 246
 	// Parent pool does not exist, add it along with corresponding bitmask
247
-	cfg.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
248
-	return func() error { return cfg.alloc.insertBitMask(cfg.ds, p.ParentKey, nw) }, nil
247
+	aSpace.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
248
+	return func() error { return aSpace.alloc.insertBitMask(p.ParentKey, nw) }, nil
249 249
 }
250 250
 
251
-func (cfg *PoolsConfig) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
252
-	cfg.Lock()
253
-	defer cfg.Unlock()
251
+func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
252
+	aSpace.Lock()
253
+	defer aSpace.Unlock()
254 254
 
255
-	p, ok := cfg.subnets[k]
255
+	p, ok := aSpace.subnets[k]
256 256
 	if !ok {
257 257
 		return nil, ipamapi.ErrBadPool
258 258
 	}
259 259
 
260
-	cfg.incRefCount(p, -1)
260
+	aSpace.incRefCount(p, -1)
261 261
 
262 262
 	c := p
263 263
 	for ok {
264 264
 		if c.RefCount == 0 {
265
-			delete(cfg.subnets, k)
265
+			delete(aSpace.subnets, k)
266 266
 			if c.Range == nil {
267 267
 				return func() error {
268
-					bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool)
268
+					bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool)
269 269
 					if err != nil {
270 270
 						return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
271 271
 					}
... ...
@@ -274,24 +324,24 @@ func (cfg *PoolsConfig) updatePoolDBOnRemoval(k SubnetKey) (func() error, error)
274 274
 			}
275 275
 		}
276 276
 		k = c.ParentKey
277
-		c, ok = cfg.subnets[k]
277
+		c, ok = aSpace.subnets[k]
278 278
 	}
279 279
 
280 280
 	return func() error { return nil }, nil
281 281
 }
282 282
 
283
-func (cfg *PoolsConfig) incRefCount(p *PoolData, delta int) {
283
+func (aSpace *addrSpace) incRefCount(p *PoolData, delta int) {
284 284
 	c := p
285 285
 	ok := true
286 286
 	for ok {
287 287
 		c.RefCount += delta
288
-		c, ok = cfg.subnets[c.ParentKey]
288
+		c, ok = aSpace.subnets[c.ParentKey]
289 289
 	}
290 290
 }
291 291
 
292 292
 // Checks whether the passed subnet is a superset or subset of any of the subset in this config db
293
-func (cfg *PoolsConfig) contains(space string, nw *net.IPNet) bool {
294
-	for k, v := range cfg.subnets {
293
+func (aSpace *addrSpace) contains(space string, nw *net.IPNet) bool {
294
+	for k, v := range aSpace.subnets {
295 295
 		if space == k.AddressSpace && k.ChildSubnet == "" {
296 296
 			if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
297 297
 				return true
... ...
@@ -300,3 +350,10 @@ func (cfg *PoolsConfig) contains(space string, nw *net.IPNet) bool {
300 300
 	}
301 301
 	return false
302 302
 }
303
+
304
+func (aSpace *addrSpace) store() datastore.DataStore {
305
+	aSpace.Lock()
306
+	defer aSpace.Unlock()
307
+
308
+	return aSpace.ds
309
+}