package executor import ( "errors" "sync" "github.com/google/uuid" ) var ErrTicketPoolFull = errors.New("ticket pool full") var ErrTicketNotTaken = errors.New("ticket not taken") var ErrTicketNotFound = errors.New("ticket not found") type Ticket struct { Index int UUID string Taken bool } type TVM struct { mutex sync.Mutex tickets map[int]*Ticket size int } func NewTVM(size int) *TVM { tickets := map[int]*Ticket{} for i := 0; i < size; i++ { tickets[i] = &Ticket{ Index: i, UUID: "", Taken: false, } } return &TVM{ tickets: tickets, size: size, } } func (this *TVM) AcquireTicket() (*Ticket, error) { this.mutex.Lock() defer this.mutex.Unlock() for i := range len(this.tickets) { if this.tickets[i].Taken { continue } this.tickets[i].UUID = uuid.New().String() this.tickets[i].Taken = true return this.tickets[i], nil } return nil, ErrTicketPoolFull } func (this *TVM) ReleaseTicket(UUID string) error { this.mutex.Lock() defer this.mutex.Unlock() for index, ticket := range this.tickets { if ticket.UUID != UUID { continue } if !ticket.Taken { return ErrTicketNotTaken } this.tickets[index].UUID = "" this.tickets[index].Taken = false return nil } return ErrTicketNotFound } func (this *TVM) FindTicket(UUID string) (*Ticket, error) { this.mutex.Lock() defer this.mutex.Unlock() for _, ticket := range this.tickets { if ticket.UUID != UUID { continue } if !ticket.Taken { return nil, ErrTicketNotTaken } return ticket, nil } return nil, ErrTicketNotFound } func (this *TVM) Capacity() int { this.mutex.Lock() defer this.mutex.Unlock() counter := 0 for i := range len(this.tickets) { if !this.tickets[i].Taken { counter += 1 } } return counter } func (this *TVM) HasTicket(UUID string) bool { this.mutex.Lock() defer this.mutex.Unlock() for _, ticket := range this.tickets { if ticket.UUID != UUID { continue } return ticket.Taken } return false }