podman

Форк
0
/
in_memory_locks.go 
148 строк · 3.2 Кб
1
package lock
2

3
import (
4
	"errors"
5
	"fmt"
6
	"sync"
7
)
8

9
// Mutex holds a single mutex and whether it has been allocated.
10
type Mutex struct {
11
	id        uint32
12
	lock      sync.Mutex
13
	allocated bool
14
}
15

16
// ID retrieves the ID of the mutex
17
func (m *Mutex) ID() uint32 {
18
	return m.id
19
}
20

21
// Lock locks the mutex
22
func (m *Mutex) Lock() {
23
	m.lock.Lock()
24
}
25

26
// Unlock unlocks the mutex
27
func (m *Mutex) Unlock() {
28
	m.lock.Unlock()
29
}
30

31
// Free deallocates the mutex to allow its reuse
32
func (m *Mutex) Free() error {
33
	m.allocated = false
34

35
	return nil
36
}
37

38
// InMemoryManager is a lock manager that allocates and retrieves local-only
39
// locks - that is, they are not multiprocess. This lock manager is intended
40
// purely for unit and integration testing and should not be used in production
41
// deployments.
42
type InMemoryManager struct {
43
	locks     []*Mutex
44
	numLocks  uint32
45
	localLock sync.Mutex
46
}
47

48
// NewInMemoryManager creates a new in-memory lock manager with the given number
49
// of locks.
50
func NewInMemoryManager(numLocks uint32) (Manager, error) {
51
	if numLocks == 0 {
52
		return nil, errors.New("must provide a non-zero number of locks")
53
	}
54

55
	manager := new(InMemoryManager)
56
	manager.numLocks = numLocks
57
	manager.locks = make([]*Mutex, numLocks)
58

59
	var i uint32
60
	for i = 0; i < numLocks; i++ {
61
		lock := new(Mutex)
62
		lock.id = i
63
		manager.locks[i] = lock
64
	}
65

66
	return manager, nil
67
}
68

69
// AllocateLock allocates a lock from the manager.
70
func (m *InMemoryManager) AllocateLock() (Locker, error) {
71
	m.localLock.Lock()
72
	defer m.localLock.Unlock()
73

74
	for _, lock := range m.locks {
75
		if !lock.allocated {
76
			lock.allocated = true
77
			return lock, nil
78
		}
79
	}
80

81
	return nil, errors.New("all locks have been allocated")
82
}
83

84
// RetrieveLock retrieves a lock from the manager.
85
func (m *InMemoryManager) RetrieveLock(id uint32) (Locker, error) {
86
	if id >= m.numLocks {
87
		return nil, fmt.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks-1)
88
	}
89

90
	return m.locks[id], nil
91
}
92

93
// AllocateAndRetrieveLock allocates a lock with the given ID (if not already in
94
// use) and returns it.
95
func (m *InMemoryManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {
96
	if id >= m.numLocks {
97
		return nil, fmt.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks)
98
	}
99

100
	if m.locks[id].allocated {
101
		return nil, fmt.Errorf("given lock ID %d is already in use, cannot reallocate", id)
102
	}
103

104
	m.locks[id].allocated = true
105

106
	return m.locks[id], nil
107
}
108

109
// FreeAllLocks frees all locks.
110
// This function is DANGEROUS. Please read the full comment in locks.go before
111
// trying to use it.
112
func (m *InMemoryManager) FreeAllLocks() error {
113
	for _, lock := range m.locks {
114
		lock.allocated = false
115
	}
116

117
	return nil
118
}
119

120
// Get number of available locks
121
func (m *InMemoryManager) AvailableLocks() (*uint32, error) {
122
	var count uint32
123

124
	for _, lock := range m.locks {
125
		if !lock.allocated {
126
			count++
127
		}
128
	}
129

130
	return &count, nil
131
}
132

133
// Get any locks that are presently being held.
134
// Useful for debugging deadlocks.
135
func (m *InMemoryManager) LocksHeld() ([]uint32, error) {
136
	//nolint:prealloc
137
	var locks []uint32
138

139
	for _, lock := range m.locks {
140
		if lock.lock.TryLock() {
141
			lock.lock.Unlock()
142
			continue
143
		}
144
		locks = append(locks, lock.ID())
145
	}
146

147
	return locks, nil
148
}
149

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.