-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(idpool): idpool feature for generating id's
Signed-off-by: Venkatesh, Vemula <venkatesh.vemula@intel.com> Signed-off-by: Atul Patel <Atul.Patel@intel.com> Signed-off-by: Vemula Venkatesh <venkatesh.vemula@intel.com>
- Loading branch information
Showing
2 changed files
with
178 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries. | ||
// Copyright (C) 2023 Nordix Foundation. | ||
|
||
// Package linuxgeneralmodule is the main package of the application | ||
|
||
package utils | ||
|
||
import ( | ||
"log" | ||
"reflect" | ||
) | ||
|
||
// IDPool structure | ||
/* Helper class for uniquely assigning IDs from a specified integer set (e.g. a | ||
# range) to keys. IDs are assigned (or read) with GetID(key) and returned back | ||
# into the pool with ReleaseID(key). The IDPool remembers a once-assigned ID | ||
# for keys so that the same ID is assigned for a key. Only when the pool runs | ||
# out of unassigned keys, it will recycle released ids and assign them to new | ||
# keys. | ||
# Optionally, the IDPool supports reference tracking for key/ID pairs. Clients | ||
# can provide a unique reference when fetching and releasing an ID for a key | ||
# to support multiple independent clients. | ||
# The pool will only release the ID for the key, when the last client has the | ||
# released the ID with its reference. When a reference is specified in GetID() | ||
# and ReleaseID() the IDPool returns the current number of reference for the | ||
# ID so that a caller knows when an ID was newly assigned (ref_count 1) or | ||
# finally released (ref_count 0). | ||
*/ | ||
type IDPool struct { | ||
name string // Name of pool | ||
_unusedids []uint32 // Yet unused IDs in pool Available ids | ||
_idsinuse map[interface{}]uint32 // Mapping key: id for currently assigned ids | ||
_idsforreuse map[interface{}]uint32 // Mapping key: id for previously assigned ids | ||
_refs map[uint32][]interface{} | ||
_size int // Size of the pool | ||
} | ||
|
||
// IDPoolInit initialize mod ptr pool | ||
func IDPoolInit(name string, min uint32, max uint32) IDPool { | ||
var pool IDPool | ||
pool.name = name | ||
pool._unusedids = make([]uint32, 0) | ||
for j := min; j <= (max + 1); j++ { | ||
pool._unusedids = append(pool._unusedids, j) | ||
} | ||
pool._size = len(pool._unusedids) | ||
pool._idsinuse = make(map[interface{}]uint32) | ||
pool._idsforreuse = make(map[interface{}]uint32) | ||
pool._refs = make(map[uint32][]interface{}) | ||
return pool | ||
} | ||
|
||
func (ip *IDPool) _assignID(key interface{}) uint32 { | ||
// Check if there was an id assigned for that key earlier | ||
id := ip._idsforreuse[key] | ||
if id != 0 { | ||
// Re-use the old id | ||
delete(ip._idsforreuse, key) | ||
} else { | ||
if len(ip._unusedids) != 0 { | ||
// Pick an unused id | ||
id = ip._unusedids[0] | ||
ip._unusedids = ip._unusedids[1:len(ip._unusedids)] | ||
} else { | ||
if len(ip._idsforreuse) != 0 { | ||
// Pick one of the ids earlier used for another key | ||
for oldKey := range ip._idsforreuse { | ||
delete(ip._idsforreuse, oldKey) | ||
break | ||
} | ||
} else { | ||
log.Printf("IDPool: Failed to allocate id for %+v. No free ids in pool.", key) | ||
return 0 | ||
} | ||
} | ||
} | ||
// Store the assigned id, if any | ||
if id != 0 { | ||
ip._idsinuse[key] = id | ||
} | ||
return id | ||
} | ||
|
||
// GetID get the mod ptr id from pool | ||
func (ip *IDPool) GetID(key interface{}, ref interface{}) (uint32, uint32) { | ||
id := ip._idsinuse[key] | ||
if id == 0 { | ||
id = ip._assignID(key) | ||
if id == 0 { | ||
return 0, 0 | ||
} | ||
} | ||
if ref != nil { | ||
log.Printf("IDPool: GetID Assigning key : %+v , id %+v for ref %v", id, key, ref) | ||
if reflect.ValueOf(ip._refs[id]).IsZero() { | ||
ip._refs[id] = make([]interface{}, 0) | ||
} | ||
ip._refs[id] = append(ip._refs[id], ref) | ||
return id, uint32(len(ip._refs[id])) | ||
} | ||
log.Printf("IDPool: GetID Assigning id %v for key %v and ref %v", id, key, ref) | ||
return id, uint32(0) | ||
} | ||
|
||
func deleteRef(refSet []interface{}, ref interface{}) []interface{} { | ||
var i uint32 | ||
for index, value := range refSet { | ||
if value == ref { | ||
i = uint32(index) | ||
break | ||
} | ||
} | ||
return append(refSet[:i], refSet[i+1:]...) | ||
} | ||
|
||
// ReleaseID get the reference id | ||
func (ip *IDPool) ReleaseID(key interface{}, ref interface{}) (uint32, uint32) { | ||
log.Printf("IDPool:ReleaseID Releasing id for key %v", key) | ||
id := ip._idsinuse[key] | ||
if ref == nil { | ||
log.Printf("No id to release for key %v", key) | ||
return 0, 0 | ||
} | ||
refSet := ip._refs[id] | ||
if !reflect.ValueOf(refSet).IsZero() && !reflect.ValueOf(ref).IsZero() { | ||
refSet = deleteRef(refSet, ref) | ||
} | ||
if refSet != nil { | ||
log.Printf("IDPool:ReleaseID Id %v has been released", id) | ||
delete(ip._idsinuse, key) | ||
if refSet != nil { | ||
delete(ip._refs, id) | ||
} | ||
// Store released id for future reassignment | ||
ip._idsforreuse[key] = id | ||
} else { | ||
log.Printf("IDPool:ReleaseID Keep id:%+v remaining references %+v", id, len(refSet)) | ||
} | ||
if ref != nil { | ||
return id, uint32(len(refSet)) | ||
} | ||
return id, uint32(0) | ||
} |