@@ -21,16 +21,25 @@ import (
2121 "os"
2222 "path/filepath"
2323 "strings"
24+ "time"
2425)
2526
27+ // nodeIP represents an IP address acquired by a node.
28+ type nodeIP struct {
29+ addr netip.Addr
30+ creationTimestamp time.Time
31+ }
32+
2633// node represents a node in the binary tree.
2734type node struct {
35+ lastUpdateTimestamp time.Time
36+
2837 prefix netip.Prefix
2938 acquired bool
3039 left * node
3140 right * node
3241
33- ips []netip. Addr
42+ ips []nodeIP
3443 lastip netip.Addr
3544}
3645
@@ -39,10 +48,12 @@ type nodeDirection string
3948const (
4049 leftDirection nodeDirection = "left"
4150 rightDirection nodeDirection = "right"
51+
52+ graphvizFolder = "./graphviz"
4253)
4354
4455func newNode (prefix netip.Prefix ) node {
45- return node {prefix : prefix }
56+ return node {prefix : prefix , lastUpdateTimestamp : time . Now () }
4657}
4758
4859func allocateNetwork (size int , node * node ) * netip.Prefix {
@@ -52,6 +63,7 @@ func allocateNetwork(size int, node *node) *netip.Prefix {
5263 if node .prefix .Bits () == size {
5364 if ! node .isSplitted () {
5465 node .acquired = true
66+ node .lastUpdateTimestamp = time .Now ()
5567 return & node .prefix
5668 }
5769 return nil
@@ -76,6 +88,7 @@ func allocateNetworkWithPrefix(prefix netip.Prefix, node *node) *netip.Prefix {
7688 if node .prefix .Addr ().Compare (prefix .Addr ()) == 0 && node .prefix .Bits () == prefix .Bits () {
7789 if ! node .acquired && node .left == nil && node .right == nil {
7890 node .acquired = true
91+ node .lastUpdateTimestamp = time .Now ()
7992 return & node .prefix
8093 }
8194 return nil
@@ -95,29 +108,31 @@ func allocateNetworkWithPrefix(prefix netip.Prefix, node *node) *netip.Prefix {
95108 return nil
96109}
97110
98- func networkRelease (prefix netip.Prefix , node * node ) * netip.Prefix {
111+ func networkRelease (prefix netip.Prefix , node * node , gracePeriod time. Duration ) * netip.Prefix {
99112 var result * netip.Prefix
100113
101114 if node == nil {
102115 return nil
103116 }
104117
105- if node .prefix .Addr ().Compare (prefix .Addr ()) == 0 && node .prefix .Bits () == prefix .Bits () {
118+ if node .prefix .Addr ().Compare (prefix .Addr ()) == 0 && node .prefix .Bits () == prefix .Bits () &&
119+ node .lastUpdateTimestamp .Add (gracePeriod ).Before (time .Now ()) {
106120 if node .acquired {
107121 node .acquired = false
122+ node .lastUpdateTimestamp = time .Now ()
108123 return & node .prefix
109124 }
110125 return nil
111126 }
112127
113128 if node .left != nil && node .left .prefix .Overlaps (prefix ) {
114- result = networkRelease (prefix , node .left )
129+ result = networkRelease (prefix , node .left , gracePeriod )
115130 }
116131 if node .right != nil && node .right .prefix .Overlaps (prefix ) {
117- result = networkRelease (prefix , node .right )
132+ result = networkRelease (prefix , node .right , gracePeriod )
118133 }
119134
120- node .merge ()
135+ node .merge (gracePeriod )
121136 return result
122137}
123138
@@ -170,7 +185,7 @@ func listNetworks(node *node) []netip.Prefix {
170185
171186func (n * node ) isAllocatedIP (ip netip.Addr ) bool {
172187 for i := range n .ips {
173- if n .ips [i ].Compare (ip ) == 0 {
188+ if n .ips [i ].addr . Compare (ip ) == 0 {
174189 return true
175190 }
176191 }
@@ -202,8 +217,9 @@ func (n *node) ipAcquire() *netip.Addr {
202217 addr = n .prefix .Addr ()
203218 }
204219 if ! n .isAllocatedIP (addr ) {
205- n .ips = append (n .ips , addr )
220+ n .ips = append (n .ips , nodeIP { addr : addr , creationTimestamp : time . Now ()} )
206221 n .lastip = addr
222+ n .lastUpdateTimestamp = time .Now ()
207223 return & addr
208224 }
209225 addr = addr .Next ()
@@ -221,25 +237,30 @@ func (n *node) allocateIPWithAddr(addr netip.Addr) *netip.Addr {
221237 }
222238
223239 for i := range n .ips {
224- if n .ips [i ].Compare (addr ) == 0 {
240+ if n .ips [i ].addr . Compare (addr ) == 0 {
225241 return nil
226242 }
227243 }
228244
229- n .ips = append (n .ips , addr )
245+ n .ips = append (n .ips , nodeIP {addr : addr , creationTimestamp : time .Now ()})
246+ n .lastUpdateTimestamp = time .Now ()
230247
231- return & n .ips [len (n .ips )- 1 ]
248+ return & n .ips [len (n .ips )- 1 ]. addr
232249}
233250
234- func (n * node ) ipRelease (ip netip.Addr ) * netip.Addr {
251+ func (n * node ) ipRelease (ip netip.Addr , gracePeriod time. Duration ) * netip.Addr {
235252 if ! n .acquired {
236253 return nil
237254 }
238255
239- for i , addr := range n .ips {
240- if addr .Compare (ip ) == 0 {
256+ for i , nodeIP := range n .ips {
257+ if ! nodeIP .creationTimestamp .Add (gracePeriod ).Before (time .Now ()) {
258+ continue
259+ }
260+ if nodeIP .addr .Compare (ip ) == 0 {
241261 n .ips = append (n .ips [:i ], n .ips [i + 1 :]... )
242- return & addr
262+ n .lastUpdateTimestamp = time .Now ()
263+ return & nodeIP .addr
243264 }
244265 }
245266 return nil
@@ -273,21 +294,33 @@ func (n *node) split() {
273294 n .insert (rightDirection , right )
274295}
275296
276- func (n * node ) merge () {
277- if n .left .isLeaf () && n .right .isLeaf () && ! n .left .acquired && ! n .right .acquired {
278- n .left = nil
279- n .right = nil
297+ func (n * node ) merge (gracePeriod time.Duration ) {
298+ if n .left == nil || n .right == nil {
299+ return
300+ }
301+ if ! n .left .lastUpdateTimestamp .Add (gracePeriod ).Before (time .Now ()) || ! n .right .lastUpdateTimestamp .Add (gracePeriod ).Before (time .Now ()) {
302+ return // grace period not expired
303+ }
304+ if ! n .left .isLeaf () || ! n .right .isLeaf () {
305+ return
280306 }
307+ if n .left .acquired || n .right .acquired {
308+ return
309+ }
310+
311+ n .left = nil
312+ n .right = nil
313+ n .lastUpdateTimestamp = time .Now ()
281314}
282315
283316func (n * node ) insert (nd nodeDirection , prefix netip.Prefix ) {
284- newNode := & node { prefix : prefix }
317+ newNode := newNode ( prefix )
285318 switch nd {
286319 case leftDirection :
287- n .left = newNode
320+ n .left = & newNode
288321 return
289322 case rightDirection :
290- n .right = newNode
323+ n .right = & newNode
291324 return
292325 default :
293326 return
@@ -335,13 +368,13 @@ func (n *node) toGraphviz() error {
335368 n .toGraphvizRecursive (& sb )
336369 sb .WriteString ("}\n " )
337370
338- if _ , err := os .Stat ("./graphviz " ); os .IsNotExist (err ) {
339- if err := os .Mkdir ("./graphviz " , 0o700 ); err != nil {
371+ if _ , err := os .Stat (graphvizFolder + " " ); os .IsNotExist (err ) {
372+ if err := os .Mkdir (graphvizFolder + " " , 0o700 ); err != nil {
340373 return err
341374 }
342375 }
343376
344- filePath := filepath .Clean ("./graphviz /" + strings .NewReplacer ("/" , "_" , "." , "_" ).Replace (n .prefix .String ()) + ".dot" )
377+ filePath := filepath .Clean (graphvizFolder + " /" + strings .NewReplacer ("/" , "_" , "." , "_" ).Replace (n .prefix .String ()) + ".dot" )
345378 file , err := os .Create (filePath )
346379 if err != nil {
347380 return err
@@ -360,7 +393,7 @@ func (n *node) toGraphvizRecursive(sb *strings.Builder) {
360393 if len (n .ips ) > 0 {
361394 ipsString := []string {}
362395 for i := range n .ips {
363- ipsString = append (ipsString , n .ips [i ].String ())
396+ ipsString = append (ipsString , n .ips [i ].addr . String ())
364397 }
365398 label += "\\ n" + strings .Join (ipsString , "\\ n" )
366399 }
0 commit comments