aboutsummaryrefslogtreecommitdiff
path: root/pkg/commands/exec.go
blob: a260f69e11ee020d5a30fb66c8c797f23f17e792 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package commands

import (
	"errors"
	"net"
	"redisClone/pkg/core"
	"sort"
)

func Exec(db core.RedisDB, session *ClientSession, conn net.Conn, execArgs []string) interface{} {
	if session.Queue == nil {
		return errors.New("EXEC without MULTI")
	}

	shardMap := make(map[int]*core.Shard)
	lockedAll := false
	var sortedIDs []int

	for _, cmdArgs := range session.Queue {
		cmdName := cmdArgs[0]
		if cmd, ok := BaseRegistry[cmdName]; ok {
			if cmd.LocksAll {
				db.LockAll()
				lockedAll = true
				break
			}
			for _, key := range cmd.ExtractKeys(cmdArgs) {
				shard := db.GetShard(key)
				shardMap[shard.Id] = shard
			}
		}
	}

	if !lockedAll {
		for id := range shardMap {
			sortedIDs = append(sortedIDs, id)
		}
		sort.Ints(sortedIDs)
		for _, id := range sortedIDs {
			shardMap[id].Mu.Lock()
		}
		
		defer func() {
			for i := len(sortedIDs) - 1; i >= 0; i-- {
				shardMap[sortedIDs[i]].Mu.Unlock()
			}
		}()
	} else {
		defer db.UnlockAll()
	}

	var results []interface{}
	
	for _, cmdArgs := range session.Queue {
		cmdName := cmdArgs[0]
		if cmd, ok := BaseRegistry[cmdName]; ok {
			// Capture the result of the command
			res := cmd.Execute(cmdArgs, db.GetShard)
			results = append(results, res)
		} else {
			results = append(results, "ERR unknown command") 
		}
	}

	session.Queue = nil

	return results
}