P1.4: tenant-индекс очередей (O(1) подсчёт/список вместо скана)

Введён тип QueueStore с индексом accessKey→{queueName}. Мутации очередей идут через
AddQueue/RemoveQueue (create/delete/restore/config/seed/admin), подсчёт и список —
через CountTenantQueues/TenantQueueNames. Устранены O(total) скан-по-префиксу в
countTenantQueues, deleteTenant, listTenantQueues, createTenantQueue. API SyncQueues
(Queues, Lock) сохранён — остальной код не затронут.
This commit is contained in:
Repinoid
2026-10-06 18:36:03 +03:00
parent fb833ef01c
commit 3a52960d5b
9 changed files with 127 additions and 62 deletions
+34 -38
View File
@@ -405,15 +405,14 @@ func (h *Handler) deleteTenant(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"error": "tenant not found"})
return
}
// Удаляем все очереди тенанта из SyncQueues
prefix := t.AccessKey + ":"
deletedQueueKeys := make([]string, 0)
// Удаляем все очереди тенанта из SyncQueues (через tenant-индекс, без скана всех очередей)
models.SyncQueues.Lock()
for key := range models.SyncQueues.Queues {
if strings.HasPrefix(key, prefix) {
deletedQueueKeys = append(deletedQueueKeys, key)
delete(models.SyncQueues.Queues, key)
}
tenantQueueNames := models.SyncQueues.TenantQueueNames(t.AccessKey)
deletedQueueKeys := make([]string, 0, len(tenantQueueNames))
for _, name := range tenantQueueNames {
key := t.AccessKey + ":" + name
deletedQueueKeys = append(deletedQueueKeys, key)
models.SyncQueues.RemoveQueue(key)
}
models.SyncQueues.Unlock()
for _, queueKey := range deletedQueueKeys {
@@ -447,27 +446,28 @@ func (h *Handler) listTenantQueues(w http.ResponseWriter, r *http.Request) {
}
queues := make([]queueInfo, 0)
models.SyncQueues.RLock()
for key, q := range models.SyncQueues.Queues {
if strings.HasPrefix(key, prefix) {
name := strings.TrimPrefix(key, prefix)
visible := 0
notVisible := 0
for _, msg := range q.Messages {
if msg.ReceiptHandle != "" {
notVisible++
} else {
visible++
}
}
queues = append(queues, queueInfo{
Name: name,
Messages: visible,
NotVisible: notVisible,
VisibilityTimeout: q.VisibilityTimeout,
MaxMessageSize: q.MaximumMessageSize,
RetentionPeriod: q.MessageRetentionPeriod,
})
for _, name := range models.SyncQueues.TenantQueueNames(t.AccessKey) {
q := models.SyncQueues.Queues[prefix+name]
if q == nil {
continue
}
visible := 0
notVisible := 0
for _, msg := range q.Messages {
if msg.ReceiptHandle != "" {
notVisible++
} else {
visible++
}
}
queues = append(queues, queueInfo{
Name: name,
Messages: visible,
NotVisible: notVisible,
VisibilityTimeout: q.VisibilityTimeout,
MaxMessageSize: q.MaximumMessageSize,
RetentionPeriod: q.MessageRetentionPeriod,
})
}
models.SyncQueues.RUnlock()
w.Header().Set("Content-Type", "application/json")
@@ -504,19 +504,14 @@ func (h *Handler) createTenantQueue(w http.ResponseWriter, r *http.Request) {
jsonErr(w, http.StatusConflict, "queue already exists")
return
}
// Проверяем лимит очередей тенанта
count := 0
for k := range models.SyncQueues.Queues {
if strings.HasPrefix(k, t.AccessKey+":") {
count++
}
}
// Проверяем лимит очередей тенанта (через tenant-индекс, O(1))
count := models.SyncQueues.CountTenantQueues(t.AccessKey)
if t.MaxQueues > 0 && count >= t.MaxQueues {
models.SyncQueues.Unlock()
jsonErr(w, http.StatusForbidden, "queue limit exceeded")
return
}
models.SyncQueues.Queues[key] = &models.Queue{
newQueue := &models.Queue{
Name: req.Name,
VisibilityTimeout: 30,
MaximumMessageSize: 262144,
@@ -524,7 +519,8 @@ func (h *Handler) createTenantQueue(w http.ResponseWriter, r *http.Request) {
Messages: []models.SqsMessage{},
Duplicates: make(map[string]time.Time),
}
persistence.SaveQueue(key, models.SyncQueues.Queues[key])
models.SyncQueues.AddQueue(key, newQueue)
persistence.SaveQueue(key, newQueue)
models.SyncQueues.Unlock()
log.Infof("admin: created queue %s for tenant %s", req.Name, t.ID)
w.Header().Set("Content-Type", "application/json")
@@ -549,7 +545,7 @@ func (h *Handler) deleteTenantQueue(w http.ResponseWriter, r *http.Request) {
jsonErr(w, http.StatusNotFound, "queue not found")
return
}
delete(models.SyncQueues.Queues, key)
models.SyncQueues.RemoveQueue(key)
models.SyncQueues.Unlock()
persistence.DeleteQueue(key)
log.Infof("admin: deleted queue %s for tenant %s", queueName, t.ID)