@@ -22,51 +22,80 @@ import org.apache.curator.framework.recipes.shared.SharedCount
22
22
import org .apache .curator .retry .RetryUntilElapsed
23
23
import org .apache .openwhisk .common .Logging
24
24
25
+ import scala .collection .JavaConverters ._
26
+
25
27
/**
26
28
* Computes the instanceId for invoker
27
29
*
28
30
* @param connectionString zooKeeper connection string
29
31
*/
30
32
private [invoker] class InstanceIdAssigner (connectionString : String )(implicit logger : Logging ) {
31
33
32
- def getId (name : String ): Int = {
34
+ def setAndGetId (name : String , overwriteId : Option [ Int ] = None ): Int = {
33
35
logger.info(this , s " invokerReg: creating zkClient to $connectionString" )
34
36
val retryPolicy = new RetryUntilElapsed (5000 , 500 ) // retry at 500ms intervals until 5 seconds have elapsed
35
37
val zkClient = CuratorFrameworkFactory .newClient(connectionString, retryPolicy)
36
38
zkClient.start()
37
39
zkClient.blockUntilConnected()
38
40
logger.info(this , " invokerReg: connected to zookeeper" )
39
41
40
- val myIdPath = " /invokers/idAssignment/mapping/" + name
41
- val assignedId = Option (zkClient.checkExists().forPath(myIdPath)) match {
42
- case None =>
43
- // path doesn't exist -> no previous mapping for this invoker
44
- logger.info(this , s " invokerReg: no prior assignment of id for invoker $name" )
45
- val idCounter = new SharedCount (zkClient, " /invokers/idAssignment/counter" , 0 )
46
- idCounter.start()
42
+ val rootPath = " /invokers/idAssignment/mapping"
43
+ val myIdPath = s " $rootPath/ $name"
44
+ val assignedId = overwriteId
45
+ .map(newId => {
46
+ val invokers = zkClient.getChildren.forPath(rootPath).asScala
47
47
48
- def assignId (): Int = {
49
- val current = idCounter.getVersionedValue()
50
- if (idCounter.trySetCount(current, current.getValue() + 1 )) {
51
- current.getValue()
52
- } else {
53
- assignId()
54
- }
55
- }
48
+ if (invokers.size < newId)
49
+ throw new IllegalArgumentException (s " invokerReg: cannot assign $newId to $name: not enough invokers " )
50
+
51
+ // check if the invokerId already exists for another unique name and delete if it does
52
+ invokers
53
+ .map(uniqueName => {
54
+ val idPath = s " $rootPath/ $uniqueName"
55
+ (idPath, BigInt (zkClient.getData.forPath(idPath)).intValue)
56
+ })
57
+ .find(_._2 == newId)
58
+ .map(id => zkClient.delete().forPath(id._1))
59
+
60
+ zkClient.create().orSetData().forPath(myIdPath, BigInt (newId).toByteArray)
56
61
57
- val newId = assignId()
58
- idCounter.close()
59
- zkClient.create().creatingParentContainersIfNeeded().forPath(myIdPath, BigInt (newId).toByteArray)
60
62
logger.info(this , s " invokerReg: invoker $name was assigned invokerId $newId" )
61
63
newId
64
+ })
65
+ .getOrElse({
66
+ Option (zkClient.checkExists().forPath(myIdPath)) match {
67
+ case None =>
68
+ // path doesn't exist -> no previous mapping for this invoker
69
+ logger.info(this , s " invokerReg: no prior assignment of id for invoker $name" )
70
+ val idCounter = new SharedCount (zkClient, " /invokers/idAssignment/counter" , 0 )
71
+ idCounter.start()
62
72
63
- case Some (_) =>
64
- // path already exists -> there is a previous mapping for this invoker we should use
65
- val rawOldId = zkClient.getData().forPath(myIdPath)
66
- val oldId = BigInt (rawOldId).intValue
67
- logger.info(this , s " invokerReg: invoker $name was assigned its previous invokerId $oldId" )
68
- oldId
69
- }
73
+ def assignId (): Int = {
74
+ val current = idCounter.getVersionedValue()
75
+ val numInvokers = Option (zkClient.checkExists().forPath(rootPath))
76
+ .map(_ => zkClient.getChildren.forPath(rootPath).size())
77
+ .getOrElse(0 )
78
+ if (idCounter.trySetCount(current, numInvokers + 1 )) {
79
+ numInvokers
80
+ } else {
81
+ assignId()
82
+ }
83
+ }
84
+
85
+ val newId = assignId()
86
+ idCounter.close()
87
+ zkClient.create().creatingParentContainersIfNeeded().forPath(myIdPath, BigInt (newId).toByteArray)
88
+ logger.info(this , s " invokerReg: invoker $name was assigned invokerId $newId" )
89
+ newId
90
+
91
+ case Some (_) =>
92
+ // path already exists -> there is a previous mapping for this invoker we should use
93
+ val rawOldId = zkClient.getData.forPath(myIdPath)
94
+ val oldId = BigInt (rawOldId).intValue
95
+ logger.info(this , s " invokerReg: invoker $name was assigned its previous invokerId $oldId" )
96
+ oldId
97
+ }
98
+ })
70
99
71
100
zkClient.close()
72
101
assignedId
0 commit comments