idm.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // Package idm manages reservation/release of numerical ids from a configured set of contiguous ids
  2. package idm
  3. import (
  4. "errors"
  5. "fmt"
  6. "github.com/docker/libnetwork/bitseq"
  7. "github.com/docker/libnetwork/datastore"
  8. )
  9. // Idm manages the reservation/release of numerical ids from a contiguous set
  10. type Idm struct {
  11. start uint64
  12. end uint64
  13. handle *bitseq.Handle
  14. }
  15. // New returns an instance of id manager for a [start,end] set of numerical ids
  16. func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
  17. if id == "" {
  18. return nil, errors.New("Invalid id")
  19. }
  20. if end <= start {
  21. return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end)
  22. }
  23. h, err := bitseq.NewHandle("idm", ds, id, 1+end-start)
  24. if err != nil {
  25. return nil, fmt.Errorf("failed to initialize bit sequence handler: %s", err.Error())
  26. }
  27. return &Idm{start: start, end: end, handle: h}, nil
  28. }
  29. // GetID returns the first available id in the set
  30. func (i *Idm) GetID() (uint64, error) {
  31. if i.handle == nil {
  32. return 0, errors.New("ID set is not initialized")
  33. }
  34. ordinal, err := i.handle.SetAny()
  35. return i.start + ordinal, err
  36. }
  37. // GetSpecificID tries to reserve the specified id
  38. func (i *Idm) GetSpecificID(id uint64) error {
  39. if i.handle == nil {
  40. return errors.New("ID set is not initialized")
  41. }
  42. if id < i.start || id > i.end {
  43. return errors.New("Requested id does not belong to the set")
  44. }
  45. return i.handle.Set(id - i.start)
  46. }
  47. // GetIDInRange returns the first available id in the set within a [start,end] range
  48. func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) {
  49. if i.handle == nil {
  50. return 0, errors.New("ID set is not initialized")
  51. }
  52. if start < i.start || end > i.end {
  53. return 0, errors.New("Requested range does not belong to the set")
  54. }
  55. ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start)
  56. return i.start + ordinal, err
  57. }
  58. // Release releases the specified id
  59. func (i *Idm) Release(id uint64) {
  60. i.handle.Unset(id - i.start)
  61. }