aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/id_alloc.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/id_alloc.go')
-rw-r--r--internal/admin/id_alloc.go43
1 files changed, 31 insertions, 12 deletions
diff --git a/internal/admin/id_alloc.go b/internal/admin/id_alloc.go
index d79718b..3a3c973 100644
--- a/internal/admin/id_alloc.go
+++ b/internal/admin/id_alloc.go
@@ -6,24 +6,43 @@ import (
"strconv"
)
-func nextRoomIDInDir(dataDir string, fromRoomID int) (int, string, error) {
- base := filepath.Join(dataDir, "rooms")
+// nextRoomID allocates a free room ID for a new room that will live in the same
+// directory as fromRoomID (so new IDs cluster near their neighbors). Unlike the
+// old per-subdir scan, the candidate is checked against EVERY room ID on disk
+// (via listRoomIDs, which walks the whole data/rooms tree), so it can never
+// collide with an ID that lives in a different subdirectory. The starting point
+// is the local subdir's minimum existing ID (clustering), then the first
+// globally-free ID scanning upward.
+func (s *AdminServer) nextRoomID(fromRoomID int) (int, string, error) {
+ base := filepath.Join(s.dataDir, "rooms")
subdir, err := findRoomSubdir(base, fromRoomID)
if err != nil {
subdir = base
}
- used := map[int]bool{}
- scanDir(subdir, used)
- if len(used) == 0 {
- return 1, subdir, nil
- }
- minID := 1<<31 - 1
- for id := range used {
- if id < minID {
- minID = id
+
+ localUsed := map[int]bool{}
+ scanDir(subdir, localUsed)
+ start := 1
+ if len(localUsed) > 0 {
+ minID := 1<<31 - 1
+ for id := range localUsed {
+ if id < minID {
+ minID = id
+ }
}
+ start = minID
+ }
+
+ globalUsed, _ := listRoomIDs(s.dataDir)
+ used := make(map[int]bool, len(globalUsed))
+ for _, id := range globalUsed {
+ used[id] = true
+ }
+
+ id := start
+ if id < 1 {
+ id = 1
}
- id := minID
for used[id] {
id++
}