diff --git a/coverage/coverage.out b/coverage/coverage.out index c3f3bdc..dec1d16 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -628,6 +628,12 @@ github.com/echovault/echovault/internal/modules/acl/user.go:290.40,305.2 1 1 github.com/echovault/echovault/internal/modules/acl/user.go:307.46,308.24 1 1 github.com/echovault/echovault/internal/modules/acl/user.go:308.24,310.3 1 1 github.com/echovault/echovault/internal/modules/acl/user.go:311.2,311.26 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:24.68,25.29 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:26.10,27.54 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:28.9,29.34 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:30.9,31.94 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:35.36,45.84 1 1 +github.com/echovault/echovault/internal/modules/connection/commands.go:45.84,51.5 1 0 github.com/echovault/echovault/internal/modules/generic/commands.go:32.67,34.16 2 1 github.com/echovault/echovault/internal/modules/generic/commands.go:34.16,36.3 1 1 github.com/echovault/echovault/internal/modules/generic/commands.go:38.2,44.16 6 1 @@ -878,12 +884,6 @@ github.com/echovault/echovault/internal/modules/generic/utils.go:107.3,109.17 3 github.com/echovault/echovault/internal/modules/generic/utils.go:109.17,111.4 1 1 github.com/echovault/echovault/internal/modules/generic/utils.go:112.3,113.55 2 1 github.com/echovault/echovault/internal/modules/generic/utils.go:115.10,116.96 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:24.68,25.29 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:26.10,27.54 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:28.9,29.34 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:30.9,31.94 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:35.36,45.84 1 1 -github.com/echovault/echovault/internal/modules/connection/commands.go:45.84,51.5 1 0 github.com/echovault/echovault/internal/modules/hash/commands.go:28.68,30.16 2 1 github.com/echovault/echovault/internal/modules/hash/commands.go:30.16,32.3 1 1 github.com/echovault/echovault/internal/modules/hash/commands.go:34.2,37.36 3 1 @@ -1367,99 +1367,6 @@ github.com/echovault/echovault/internal/modules/list/key_funcs.go:115.2,119.8 1 github.com/echovault/echovault/internal/modules/list/key_funcs.go:122.75,123.19 1 1 github.com/echovault/echovault/internal/modules/list/key_funcs.go:123.19,125.3 1 1 github.com/echovault/echovault/internal/modules/list/key_funcs.go:126.2,130.8 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:27.78,33.29 4 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:33.29,34.54 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:34.54,40.42 4 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:40.42,42.5 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:44.4,47.12 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:50.3,50.36 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:50.36,57.43 5 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:57.43,59.5 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:61.4,63.21 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:67.2,69.25 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:72.76,76.35 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:76.35,77.65 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:77.65,78.41 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:78.41,80.5 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:81.4,81.12 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:83.3,83.13 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:86.2,86.51 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:89.75,90.29 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:91.9,96.36 4 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:96.36,97.66 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:97.66,98.52 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:98.52,102.6 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:103.5,103.13 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:105.4,106.14 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:108.3,109.26 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:111.9,115.56 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:115.56,117.4 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:118.3,118.53 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:118.53,122.37 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:122.37,123.67 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:123.67,124.53 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:124.53,125.59 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:125.59,129.8 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:131.6,131.14 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:133.5,133.54 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:133.54,136.6 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:138.9,138.61 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:138.61,142.37 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:142.37,143.67 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:143.67,144.53 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:144.53,146.24 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:146.24,149.8 2 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:151.6,151.14 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:153.5,153.33 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:153.33,156.6 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:158.9,158.60 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:158.60,162.37 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:162.37,163.67 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:163.67,164.53 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:164.53,165.55 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:165.55,169.8 3 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:171.6,171.14 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:173.5,173.50 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:173.50,176.6 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:178.9,180.4 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:181.3,182.26 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:183.10,184.54 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:188.75,190.2 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:192.36,200.84 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:200.84,204.5 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:213.84,217.5 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:225.86,229.7 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:238.86,242.7 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:252.86,256.7 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:267.84,271.5 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:272.73,273.49 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:273.49,275.6 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:276.5,276.45 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:285.84,289.5 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:290.73,292.18 2 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:292.18,294.6 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:295.5,295.53 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:304.84,308.5 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:309.73,310.47 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:310.47,312.6 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:313.5,313.45 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:321.84,325.5 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:335.86,339.7 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:340.75,341.34 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:341.34,343.8 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:344.7,345.34 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:345.34,347.8 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:348.7,348.75 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:348.75,350.8 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:351.7,351.47 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:361.86,365.7 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:366.75,367.35 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:367.35,369.8 1 0 -github.com/echovault/echovault/internal/modules/admin/commands.go:370.7,371.47 2 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:380.86,384.7 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:385.75,388.38 3 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:388.38,390.8 1 1 -github.com/echovault/echovault/internal/modules/admin/commands.go:391.7,391.30 1 1 github.com/echovault/echovault/internal/modules/pubsub/channel.go:34.51,35.32 1 1 github.com/echovault/echovault/internal/modules/pubsub/channel.go:35.32,37.3 1 1 github.com/echovault/echovault/internal/modules/pubsub/channel.go:41.57,42.32 1 1 @@ -2021,6 +1928,99 @@ github.com/echovault/echovault/internal/modules/set/set.go:184.31,185.19 1 1 github.com/echovault/echovault/internal/modules/set/set.go:186.9,187.17 1 1 github.com/echovault/echovault/internal/modules/set/set.go:188.9,191.15 3 1 github.com/echovault/echovault/internal/modules/set/set.go:192.10,195.28 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:27.78,33.29 4 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:33.29,34.54 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:34.54,40.42 4 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:40.42,42.5 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:44.4,47.12 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:50.3,50.36 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:50.36,57.43 5 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:57.43,59.5 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:61.4,63.21 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:67.2,69.25 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:72.76,76.35 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:76.35,77.65 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:77.65,78.41 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:78.41,80.5 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:81.4,81.12 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:83.3,83.13 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:86.2,86.51 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:89.75,90.29 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:91.9,96.36 4 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:96.36,97.66 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:97.66,98.52 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:98.52,102.6 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:103.5,103.13 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:105.4,106.14 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:108.3,109.26 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:111.9,115.56 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:115.56,117.4 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:118.3,118.53 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:118.53,122.37 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:122.37,123.67 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:123.67,124.53 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:124.53,125.59 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:125.59,129.8 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:131.6,131.14 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:133.5,133.54 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:133.54,136.6 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:138.9,138.61 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:138.61,142.37 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:142.37,143.67 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:143.67,144.53 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:144.53,146.24 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:146.24,149.8 2 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:151.6,151.14 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:153.5,153.33 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:153.33,156.6 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:158.9,158.60 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:158.60,162.37 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:162.37,163.67 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:163.67,164.53 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:164.53,165.55 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:165.55,169.8 3 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:171.6,171.14 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:173.5,173.50 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:173.50,176.6 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:178.9,180.4 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:181.3,182.26 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:183.10,184.54 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:188.75,190.2 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:192.36,200.84 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:200.84,204.5 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:213.84,217.5 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:225.86,229.7 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:238.86,242.7 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:252.86,256.7 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:267.84,271.5 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:272.73,273.49 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:273.49,275.6 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:276.5,276.45 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:285.84,289.5 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:290.73,292.18 2 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:292.18,294.6 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:295.5,295.53 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:304.84,308.5 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:309.73,310.47 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:310.47,312.6 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:313.5,313.45 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:321.84,325.5 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:335.86,339.7 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:340.75,341.34 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:341.34,343.8 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:344.7,345.34 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:345.34,347.8 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:348.7,348.75 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:348.75,350.8 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:351.7,351.47 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:361.86,365.7 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:366.75,367.35 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:367.35,369.8 1 0 +github.com/echovault/echovault/internal/modules/admin/commands.go:370.7,371.47 2 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:380.86,384.7 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:385.75,388.38 3 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:388.38,390.8 1 1 +github.com/echovault/echovault/internal/modules/admin/commands.go:391.7,391.30 1 1 github.com/echovault/echovault/internal/modules/sorted_set/commands.go:29.68,31.16 2 1 github.com/echovault/echovault/internal/modules/sorted_set/commands.go:31.16,33.3 1 1 github.com/echovault/echovault/internal/modules/sorted_set/commands.go:35.2,44.43 7 1 @@ -3753,154 +3753,154 @@ github.com/echovault/echovault/echovault/cluster.go:91.2,91.20 1 1 github.com/echovault/echovault/echovault/cluster.go:91.20,93.3 1 0 github.com/echovault/echovault/echovault/cluster.go:95.2,95.24 1 1 github.com/echovault/echovault/echovault/config.go:23.36,25.2 1 1 -github.com/echovault/echovault/echovault/echovault.go:112.66,113.36 1 0 -github.com/echovault/echovault/echovault/echovault.go:113.36,115.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:121.66,122.36 1 1 -github.com/echovault/echovault/echovault/echovault.go:122.36,124.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:129.78,138.39 1 1 -github.com/echovault/echovault/echovault/echovault.go:138.39,151.4 12 1 -github.com/echovault/echovault/echovault/echovault.go:154.2,154.33 1 1 -github.com/echovault/echovault/echovault/echovault.go:154.33,156.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:158.2,164.48 2 1 -github.com/echovault/echovault/echovault/echovault.go:164.48,165.52 1 0 -github.com/echovault/echovault/echovault/echovault.go:165.52,167.12 2 0 -github.com/echovault/echovault/echovault/echovault.go:169.3,169.41 1 0 -github.com/echovault/echovault/echovault/echovault.go:173.2,173.52 1 1 -github.com/echovault/echovault/echovault/echovault.go:173.52,175.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:178.2,178.42 1 1 -github.com/echovault/echovault/echovault/echovault.go:178.42,180.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:183.2,184.40 2 1 -github.com/echovault/echovault/echovault/echovault.go:184.40,186.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:189.2,190.43 2 1 -github.com/echovault/echovault/echovault/echovault.go:190.43,192.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:194.2,194.29 1 1 -github.com/echovault/echovault/echovault/echovault.go:194.29,207.49 1 1 -github.com/echovault/echovault/echovault/echovault.go:207.49,209.44 2 0 -github.com/echovault/echovault/echovault/echovault.go:209.44,210.46 1 0 -github.com/echovault/echovault/echovault/echovault.go:210.46,212.7 1 0 -github.com/echovault/echovault/echovault/echovault.go:214.5,214.17 1 0 -github.com/echovault/echovault/echovault/echovault.go:217.3,225.5 1 1 -github.com/echovault/echovault/echovault/echovault.go:226.8,237.65 1 1 -github.com/echovault/echovault/echovault/echovault.go:237.65,239.44 2 0 -github.com/echovault/echovault/echovault/echovault.go:239.44,240.46 1 0 -github.com/echovault/echovault/echovault/echovault.go:240.46,242.7 1 0 -github.com/echovault/echovault/echovault/echovault.go:244.5,244.17 1 0 -github.com/echovault/echovault/echovault/echovault.go:246.72,248.67 2 0 -github.com/echovault/echovault/echovault/echovault.go:248.67,250.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:251.5,251.68 1 0 -github.com/echovault/echovault/echovault/echovault.go:251.68,253.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:254.5,255.34 2 0 -github.com/echovault/echovault/echovault/echovault.go:259.3,265.60 1 1 -github.com/echovault/echovault/echovault/echovault.go:265.60,267.44 2 0 -github.com/echovault/echovault/echovault/echovault.go:267.44,268.46 1 0 -github.com/echovault/echovault/echovault/echovault.go:268.46,270.7 1 0 -github.com/echovault/echovault/echovault/echovault.go:272.5,272.17 1 0 -github.com/echovault/echovault/echovault/echovault.go:274.68,276.67 2 0 -github.com/echovault/echovault/echovault/echovault.go:276.67,278.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:279.5,279.69 1 0 -github.com/echovault/echovault/echovault/echovault.go:279.69,281.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:282.5,283.34 2 0 -github.com/echovault/echovault/echovault/echovault.go:285.51,287.19 2 0 -github.com/echovault/echovault/echovault/echovault.go:287.19,289.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:292.3,292.17 1 1 -github.com/echovault/echovault/echovault/echovault.go:292.17,294.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:295.3,295.34 1 1 -github.com/echovault/echovault/echovault/echovault.go:299.2,299.61 1 1 -github.com/echovault/echovault/echovault/echovault.go:299.61,300.13 1 1 -github.com/echovault/echovault/echovault/echovault.go:300.13,301.8 1 1 -github.com/echovault/echovault/echovault/echovault.go:301.8,303.83 2 1 -github.com/echovault/echovault/echovault/echovault.go:303.83,305.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:310.2,310.69 1 1 -github.com/echovault/echovault/echovault/echovault.go:310.69,312.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:314.2,314.29 1 1 -github.com/echovault/echovault/echovault/echovault.go:314.29,318.36 3 1 -github.com/echovault/echovault/echovault/echovault.go:318.36,320.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:323.2,323.30 1 1 -github.com/echovault/echovault/echovault/echovault.go:323.30,326.34 2 1 -github.com/echovault/echovault/echovault/echovault.go:326.34,328.18 2 0 -github.com/echovault/echovault/echovault/echovault.go:328.18,330.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:334.3,334.71 1 1 -github.com/echovault/echovault/echovault/echovault.go:334.71,336.18 2 0 -github.com/echovault/echovault/echovault/echovault.go:336.18,338.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:342.2,342.23 1 1 -github.com/echovault/echovault/echovault/echovault.go:345.37,354.16 4 1 -github.com/echovault/echovault/echovault/echovault.go:354.16,356.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:358.2,358.15 1 1 -github.com/echovault/echovault/echovault/echovault.go:358.15,361.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:363.2,363.27 1 1 -github.com/echovault/echovault/echovault/echovault.go:363.27,365.15 1 0 -github.com/echovault/echovault/echovault/echovault.go:365.15,367.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:367.9,369.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:371.3,372.49 2 0 -github.com/echovault/echovault/echovault/echovault.go:372.49,374.18 2 0 -github.com/echovault/echovault/echovault/echovault.go:374.18,376.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:377.4,377.42 1 0 -github.com/echovault/echovault/echovault/echovault.go:380.3,383.16 3 0 -github.com/echovault/echovault/echovault/echovault.go:383.16,385.37 2 0 -github.com/echovault/echovault/echovault/echovault.go:385.37,387.19 2 0 -github.com/echovault/echovault/echovault/echovault.go:387.19,389.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:390.5,391.19 2 0 -github.com/echovault/echovault/echovault/echovault.go:391.19,393.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:394.5,394.61 1 0 -github.com/echovault/echovault/echovault/echovault.go:394.61,396.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:400.3,404.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:408.2,408.6 1 1 -github.com/echovault/echovault/echovault/echovault.go:408.6,410.17 2 1 -github.com/echovault/echovault/echovault/echovault.go:410.17,412.12 2 0 -github.com/echovault/echovault/echovault/echovault.go:415.3,415.35 1 1 -github.com/echovault/echovault/echovault/echovault.go:419.58,421.23 1 1 -github.com/echovault/echovault/echovault/echovault.go:421.23,423.3 1 1 -github.com/echovault/echovault/echovault/echovault.go:425.2,431.6 4 1 -github.com/echovault/echovault/echovault/echovault.go:431.6,434.43 2 1 -github.com/echovault/echovault/echovault/echovault.go:434.43,437.9 2 0 -github.com/echovault/echovault/echovault/echovault.go:440.3,440.17 1 1 -github.com/echovault/echovault/echovault/echovault.go:440.17,442.9 2 0 -github.com/echovault/echovault/echovault/echovault.go:445.3,447.43 2 1 -github.com/echovault/echovault/echovault/echovault.go:447.43,448.9 1 0 -github.com/echovault/echovault/echovault/echovault.go:451.3,451.17 1 1 -github.com/echovault/echovault/echovault/echovault.go:451.17,452.87 1 0 -github.com/echovault/echovault/echovault/echovault.go:452.87,454.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:455.4,455.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:458.3,461.20 2 1 -github.com/echovault/echovault/echovault/echovault.go:461.20,462.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:465.3,465.28 1 1 -github.com/echovault/echovault/echovault/echovault.go:465.28,467.12 2 1 -github.com/echovault/echovault/echovault/echovault.go:471.3,472.7 2 0 -github.com/echovault/echovault/echovault/echovault.go:472.7,474.41 1 0 -github.com/echovault/echovault/echovault/echovault.go:474.41,476.19 2 0 -github.com/echovault/echovault/echovault/echovault.go:476.19,478.6 1 0 -github.com/echovault/echovault/echovault/echovault.go:479.5,479.10 1 0 -github.com/echovault/echovault/echovault/echovault.go:481.4,482.21 2 0 -github.com/echovault/echovault/echovault/echovault.go:482.21,483.10 1 0 -github.com/echovault/echovault/echovault/echovault.go:485.4,485.27 1 0 -github.com/echovault/echovault/echovault/echovault.go:489.2,489.37 1 0 -github.com/echovault/echovault/echovault/echovault.go:489.37,491.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:499.34,501.2 1 1 -github.com/echovault/echovault/echovault/echovault.go:504.47,505.38 1 0 -github.com/echovault/echovault/echovault/echovault.go:505.38,507.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:509.2,509.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:509.12,510.27 1 0 -github.com/echovault/echovault/echovault/echovault.go:510.27,512.53 1 0 -github.com/echovault/echovault/echovault/echovault.go:512.53,514.5 1 0 -github.com/echovault/echovault/echovault/echovault.go:515.4,515.10 1 0 -github.com/echovault/echovault/echovault/echovault.go:518.3,518.62 1 0 -github.com/echovault/echovault/echovault/echovault.go:518.62,520.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:523.2,523.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:526.42,528.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:530.43,532.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:534.56,536.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:539.56,541.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:543.44,545.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:547.45,549.2 1 0 -github.com/echovault/echovault/echovault/echovault.go:552.45,553.40 1 0 -github.com/echovault/echovault/echovault/echovault.go:553.40,555.3 1 0 -github.com/echovault/echovault/echovault/echovault.go:556.2,556.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:556.12,557.55 1 0 -github.com/echovault/echovault/echovault/echovault.go:557.55,559.4 1 0 -github.com/echovault/echovault/echovault/echovault.go:561.2,561.12 1 0 -github.com/echovault/echovault/echovault/echovault.go:566.37,567.26 1 0 -github.com/echovault/echovault/echovault/echovault.go:567.26,570.3 2 0 -github.com/echovault/echovault/echovault/echovault.go:573.45,590.2 2 1 +github.com/echovault/echovault/echovault/echovault.go:113.66,114.36 1 0 +github.com/echovault/echovault/echovault/echovault.go:114.36,116.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:122.66,123.36 1 1 +github.com/echovault/echovault/echovault/echovault.go:123.36,125.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:130.78,140.39 1 1 +github.com/echovault/echovault/echovault/echovault.go:140.39,153.4 12 1 +github.com/echovault/echovault/echovault/echovault.go:156.2,156.33 1 1 +github.com/echovault/echovault/echovault/echovault.go:156.33,158.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:160.2,166.48 2 1 +github.com/echovault/echovault/echovault/echovault.go:166.48,167.52 1 0 +github.com/echovault/echovault/echovault/echovault.go:167.52,169.12 2 0 +github.com/echovault/echovault/echovault/echovault.go:171.3,171.41 1 0 +github.com/echovault/echovault/echovault/echovault.go:175.2,175.52 1 1 +github.com/echovault/echovault/echovault/echovault.go:175.52,177.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:180.2,180.42 1 1 +github.com/echovault/echovault/echovault/echovault.go:180.42,182.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:185.2,186.40 2 1 +github.com/echovault/echovault/echovault/echovault.go:186.40,188.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:191.2,192.43 2 1 +github.com/echovault/echovault/echovault/echovault.go:192.43,194.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:196.2,196.29 1 1 +github.com/echovault/echovault/echovault/echovault.go:196.29,209.49 1 1 +github.com/echovault/echovault/echovault/echovault.go:209.49,211.44 2 0 +github.com/echovault/echovault/echovault/echovault.go:211.44,212.46 1 0 +github.com/echovault/echovault/echovault/echovault.go:212.46,214.7 1 0 +github.com/echovault/echovault/echovault/echovault.go:216.5,216.17 1 0 +github.com/echovault/echovault/echovault/echovault.go:219.3,227.5 1 1 +github.com/echovault/echovault/echovault/echovault.go:228.8,239.65 1 1 +github.com/echovault/echovault/echovault/echovault.go:239.65,241.44 2 0 +github.com/echovault/echovault/echovault/echovault.go:241.44,242.46 1 0 +github.com/echovault/echovault/echovault/echovault.go:242.46,244.7 1 0 +github.com/echovault/echovault/echovault/echovault.go:246.5,246.17 1 0 +github.com/echovault/echovault/echovault/echovault.go:248.72,250.67 2 0 +github.com/echovault/echovault/echovault/echovault.go:250.67,252.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:253.5,253.68 1 0 +github.com/echovault/echovault/echovault/echovault.go:253.68,255.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:256.5,257.34 2 0 +github.com/echovault/echovault/echovault/echovault.go:261.3,267.60 1 1 +github.com/echovault/echovault/echovault/echovault.go:267.60,269.44 2 0 +github.com/echovault/echovault/echovault/echovault.go:269.44,270.46 1 0 +github.com/echovault/echovault/echovault/echovault.go:270.46,272.7 1 0 +github.com/echovault/echovault/echovault/echovault.go:274.5,274.17 1 0 +github.com/echovault/echovault/echovault/echovault.go:276.68,278.67 2 0 +github.com/echovault/echovault/echovault/echovault.go:278.67,280.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:281.5,281.69 1 0 +github.com/echovault/echovault/echovault/echovault.go:281.69,283.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:284.5,285.34 2 0 +github.com/echovault/echovault/echovault/echovault.go:287.51,289.19 2 0 +github.com/echovault/echovault/echovault/echovault.go:289.19,291.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:294.3,294.17 1 1 +github.com/echovault/echovault/echovault/echovault.go:294.17,296.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:297.3,297.34 1 1 +github.com/echovault/echovault/echovault/echovault.go:301.2,301.61 1 1 +github.com/echovault/echovault/echovault/echovault.go:301.61,302.13 1 1 +github.com/echovault/echovault/echovault/echovault.go:302.13,303.8 1 1 +github.com/echovault/echovault/echovault/echovault.go:303.8,305.83 2 1 +github.com/echovault/echovault/echovault/echovault.go:305.83,307.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:312.2,312.69 1 1 +github.com/echovault/echovault/echovault/echovault.go:312.69,314.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:316.2,316.29 1 1 +github.com/echovault/echovault/echovault/echovault.go:316.29,320.36 3 1 +github.com/echovault/echovault/echovault/echovault.go:320.36,322.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:325.2,325.30 1 1 +github.com/echovault/echovault/echovault/echovault.go:325.30,328.34 2 1 +github.com/echovault/echovault/echovault/echovault.go:328.34,330.18 2 0 +github.com/echovault/echovault/echovault/echovault.go:330.18,332.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:336.3,336.71 1 1 +github.com/echovault/echovault/echovault/echovault.go:336.71,338.18 2 0 +github.com/echovault/echovault/echovault/echovault.go:338.18,340.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:344.2,344.23 1 1 +github.com/echovault/echovault/echovault/echovault.go:347.37,356.16 4 1 +github.com/echovault/echovault/echovault/echovault.go:356.16,358.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:360.2,360.15 1 1 +github.com/echovault/echovault/echovault/echovault.go:360.15,363.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:365.2,365.27 1 1 +github.com/echovault/echovault/echovault/echovault.go:365.27,367.15 1 0 +github.com/echovault/echovault/echovault/echovault.go:367.15,369.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:369.9,371.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:373.3,374.49 2 0 +github.com/echovault/echovault/echovault/echovault.go:374.49,376.18 2 0 +github.com/echovault/echovault/echovault/echovault.go:376.18,378.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:379.4,379.42 1 0 +github.com/echovault/echovault/echovault/echovault.go:382.3,385.16 3 0 +github.com/echovault/echovault/echovault/echovault.go:385.16,387.37 2 0 +github.com/echovault/echovault/echovault/echovault.go:387.37,389.19 2 0 +github.com/echovault/echovault/echovault/echovault.go:389.19,391.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:392.5,393.19 2 0 +github.com/echovault/echovault/echovault/echovault.go:393.19,395.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:396.5,396.61 1 0 +github.com/echovault/echovault/echovault/echovault.go:396.61,398.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:402.3,406.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:410.2,410.6 1 1 +github.com/echovault/echovault/echovault/echovault.go:410.6,412.17 2 1 +github.com/echovault/echovault/echovault/echovault.go:412.17,414.12 2 0 +github.com/echovault/echovault/echovault/echovault.go:417.3,417.35 1 1 +github.com/echovault/echovault/echovault/echovault.go:421.58,423.23 1 1 +github.com/echovault/echovault/echovault/echovault.go:423.23,425.3 1 1 +github.com/echovault/echovault/echovault/echovault.go:427.2,433.6 4 1 +github.com/echovault/echovault/echovault/echovault.go:433.6,436.43 2 1 +github.com/echovault/echovault/echovault/echovault.go:436.43,439.9 2 0 +github.com/echovault/echovault/echovault/echovault.go:442.3,442.17 1 1 +github.com/echovault/echovault/echovault/echovault.go:442.17,444.9 2 0 +github.com/echovault/echovault/echovault/echovault.go:447.3,449.43 2 1 +github.com/echovault/echovault/echovault/echovault.go:449.43,450.9 1 0 +github.com/echovault/echovault/echovault/echovault.go:453.3,453.17 1 1 +github.com/echovault/echovault/echovault/echovault.go:453.17,454.87 1 0 +github.com/echovault/echovault/echovault/echovault.go:454.87,456.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:457.4,457.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:460.3,463.20 2 1 +github.com/echovault/echovault/echovault/echovault.go:463.20,464.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:467.3,467.28 1 1 +github.com/echovault/echovault/echovault/echovault.go:467.28,469.12 2 1 +github.com/echovault/echovault/echovault/echovault.go:473.3,474.7 2 0 +github.com/echovault/echovault/echovault/echovault.go:474.7,476.41 1 0 +github.com/echovault/echovault/echovault/echovault.go:476.41,478.19 2 0 +github.com/echovault/echovault/echovault/echovault.go:478.19,480.6 1 0 +github.com/echovault/echovault/echovault/echovault.go:481.5,481.10 1 0 +github.com/echovault/echovault/echovault/echovault.go:483.4,484.21 2 0 +github.com/echovault/echovault/echovault/echovault.go:484.21,485.10 1 0 +github.com/echovault/echovault/echovault/echovault.go:487.4,487.27 1 0 +github.com/echovault/echovault/echovault/echovault.go:491.2,491.37 1 0 +github.com/echovault/echovault/echovault/echovault.go:491.37,493.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:501.34,503.2 1 1 +github.com/echovault/echovault/echovault/echovault.go:506.47,507.38 1 0 +github.com/echovault/echovault/echovault/echovault.go:507.38,509.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:511.2,511.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:511.12,512.27 1 0 +github.com/echovault/echovault/echovault/echovault.go:512.27,514.53 1 0 +github.com/echovault/echovault/echovault/echovault.go:514.53,516.5 1 0 +github.com/echovault/echovault/echovault/echovault.go:517.4,517.10 1 0 +github.com/echovault/echovault/echovault/echovault.go:520.3,520.62 1 0 +github.com/echovault/echovault/echovault/echovault.go:520.62,522.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:525.2,525.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:528.42,530.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:532.43,534.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:536.56,538.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:541.56,543.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:545.44,547.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:549.45,551.2 1 0 +github.com/echovault/echovault/echovault/echovault.go:554.45,555.40 1 0 +github.com/echovault/echovault/echovault/echovault.go:555.40,557.3 1 0 +github.com/echovault/echovault/echovault/echovault.go:558.2,558.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:558.12,559.55 1 0 +github.com/echovault/echovault/echovault/echovault.go:559.55,561.4 1 0 +github.com/echovault/echovault/echovault/echovault.go:563.2,563.12 1 0 +github.com/echovault/echovault/echovault/echovault.go:568.37,569.26 1 0 +github.com/echovault/echovault/echovault/echovault.go:569.26,572.3 2 0 +github.com/echovault/echovault/echovault/echovault.go:575.45,592.2 2 1 github.com/echovault/echovault/echovault/keyspace.go:38.81,41.34 2 1 github.com/echovault/echovault/echovault/keyspace.go:41.34,44.3 2 1 github.com/echovault/echovault/echovault/keyspace.go:46.2,46.6 1 1 @@ -3923,147 +3923,147 @@ github.com/echovault/echovault/echovault/keyspace.go:92.10,94.5 1 1 github.com/echovault/echovault/echovault/keyspace.go:95.21,96.36 1 0 github.com/echovault/echovault/echovault/keyspace.go:105.68,106.39 1 1 github.com/echovault/echovault/echovault/keyspace.go:106.39,108.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:116.74,118.9 2 1 -github.com/echovault/echovault/echovault/keyspace.go:118.9,120.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:122.2,122.82 1 1 -github.com/echovault/echovault/echovault/keyspace.go:122.82,123.28 1 0 -github.com/echovault/echovault/echovault/keyspace.go:123.28,126.18 2 0 -github.com/echovault/echovault/echovault/keyspace.go:126.18,128.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:129.9,129.64 1 0 -github.com/echovault/echovault/echovault/keyspace.go:129.64,132.18 2 0 -github.com/echovault/echovault/echovault/keyspace.go:132.18,134.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:135.9,135.65 1 0 -github.com/echovault/echovault/echovault/keyspace.go:135.65,140.4 1 0 -github.com/echovault/echovault/echovault/keyspace.go:142.3,142.15 1 0 -github.com/echovault/echovault/echovault/keyspace.go:145.2,145.13 1 1 -github.com/echovault/echovault/echovault/keyspace.go:153.90,154.115 1 1 -github.com/echovault/echovault/echovault/keyspace.go:154.115,156.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:158.2,161.33 3 1 -github.com/echovault/echovault/echovault/keyspace.go:161.33,172.3 5 1 -github.com/echovault/echovault/echovault/keyspace.go:174.2,174.33 1 1 -github.com/echovault/echovault/echovault/keyspace.go:179.80,180.58 1 1 -github.com/echovault/echovault/echovault/keyspace.go:180.58,182.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:183.2,183.32 1 1 -github.com/echovault/echovault/echovault/keyspace.go:190.93,191.115 1 1 -github.com/echovault/echovault/echovault/keyspace.go:191.115,193.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:195.2,201.16 3 1 -github.com/echovault/echovault/echovault/keyspace.go:201.16,203.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:205.2,205.27 1 1 -github.com/echovault/echovault/echovault/keyspace.go:205.27,207.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:209.2,209.12 1 1 -github.com/echovault/echovault/echovault/keyspace.go:214.79,215.58 1 1 -github.com/echovault/echovault/echovault/keyspace.go:215.58,217.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:218.2,218.35 1 1 -github.com/echovault/echovault/echovault/keyspace.go:227.101,235.55 3 1 -github.com/echovault/echovault/echovault/keyspace.go:235.55,237.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:238.2,241.11 2 1 -github.com/echovault/echovault/echovault/keyspace.go:241.11,243.17 2 1 -github.com/echovault/echovault/echovault/keyspace.go:243.17,245.4 1 0 -github.com/echovault/echovault/echovault/keyspace.go:251.70,260.97 4 1 -github.com/echovault/echovault/echovault/keyspace.go:260.97,262.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:270.60,272.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:272.6,273.83 1 0 -github.com/echovault/echovault/echovault/keyspace.go:273.83,275.9 2 0 -github.com/echovault/echovault/echovault/keyspace.go:278.2,279.33 2 0 -github.com/echovault/echovault/echovault/keyspace.go:279.33,281.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:282.2,283.13 2 0 -github.com/echovault/echovault/echovault/keyspace.go:290.75,291.52 1 1 -github.com/echovault/echovault/echovault/keyspace.go:291.52,293.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:296.2,303.9 4 1 -github.com/echovault/echovault/echovault/keyspace.go:304.108,305.36 1 0 -github.com/echovault/echovault/echovault/keyspace.go:306.108,307.36 1 0 -github.com/echovault/echovault/echovault/keyspace.go:312.2,312.12 1 1 -github.com/echovault/echovault/echovault/keyspace.go:317.82,319.83 1 1 -github.com/echovault/echovault/echovault/keyspace.go:319.83,321.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:323.2,323.34 1 1 -github.com/echovault/echovault/echovault/keyspace.go:323.34,325.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:326.2,326.55 1 0 -github.com/echovault/echovault/echovault/keyspace.go:327.28,330.36 3 0 -github.com/echovault/echovault/echovault/keyspace.go:331.28,334.36 3 0 -github.com/echovault/echovault/echovault/keyspace.go:335.29,338.50 3 0 -github.com/echovault/echovault/echovault/keyspace.go:338.50,340.4 1 0 -github.com/echovault/echovault/echovault/keyspace.go:341.29,344.50 3 0 -github.com/echovault/echovault/echovault/keyspace.go:344.50,346.4 1 0 -github.com/echovault/echovault/echovault/keyspace.go:348.2,348.54 1 0 -github.com/echovault/echovault/echovault/keyspace.go:348.54,350.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:351.2,351.12 1 0 -github.com/echovault/echovault/echovault/keyspace.go:355.71,357.34 1 0 -github.com/echovault/echovault/echovault/keyspace.go:357.34,359.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:362.2,365.50 3 0 -github.com/echovault/echovault/echovault/keyspace.go:365.50,367.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:369.2,371.50 3 0 -github.com/echovault/echovault/echovault/keyspace.go:371.50,373.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:377.2,377.9 1 0 -github.com/echovault/echovault/echovault/keyspace.go:378.125,383.7 3 0 -github.com/echovault/echovault/echovault/keyspace.go:383.7,385.40 1 0 -github.com/echovault/echovault/echovault/keyspace.go:385.40,387.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:389.4,390.29 2 0 -github.com/echovault/echovault/echovault/keyspace.go:390.29,392.54 1 0 -github.com/echovault/echovault/echovault/keyspace.go:392.54,394.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:395.10,395.65 1 0 -github.com/echovault/echovault/echovault/keyspace.go:395.65,397.63 1 0 -github.com/echovault/echovault/echovault/keyspace.go:397.63,399.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:403.4,406.52 3 0 -github.com/echovault/echovault/echovault/keyspace.go:406.52,408.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:410.125,415.7 3 0 -github.com/echovault/echovault/echovault/keyspace.go:415.7,417.40 1 0 -github.com/echovault/echovault/echovault/keyspace.go:417.40,419.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:421.4,422.29 2 0 -github.com/echovault/echovault/echovault/keyspace.go:422.29,424.54 1 0 -github.com/echovault/echovault/echovault/keyspace.go:424.54,426.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:427.10,427.65 1 0 -github.com/echovault/echovault/echovault/keyspace.go:427.65,430.63 1 0 -github.com/echovault/echovault/echovault/keyspace.go:430.63,432.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:436.4,439.52 3 0 -github.com/echovault/echovault/echovault/keyspace.go:439.52,441.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:443.105,446.7 1 0 -github.com/echovault/echovault/echovault/keyspace.go:446.7,448.33 1 0 -github.com/echovault/echovault/echovault/keyspace.go:448.33,451.5 2 0 -github.com/echovault/echovault/echovault/keyspace.go:453.4,454.40 2 0 -github.com/echovault/echovault/echovault/keyspace.go:454.40,455.17 1 0 -github.com/echovault/echovault/echovault/keyspace.go:455.17,456.31 1 0 -github.com/echovault/echovault/echovault/keyspace.go:456.31,458.56 1 0 -github.com/echovault/echovault/echovault/keyspace.go:458.56,460.8 1 0 -github.com/echovault/echovault/echovault/keyspace.go:461.12,461.67 1 0 -github.com/echovault/echovault/echovault/keyspace.go:461.67,462.65 1 0 -github.com/echovault/echovault/echovault/keyspace.go:462.65,464.8 1 0 -github.com/echovault/echovault/echovault/keyspace.go:467.6,470.54 3 0 -github.com/echovault/echovault/echovault/keyspace.go:470.54,472.7 1 0 -github.com/echovault/echovault/echovault/keyspace.go:474.5,474.10 1 0 -github.com/echovault/echovault/echovault/keyspace.go:477.106,480.7 1 0 -github.com/echovault/echovault/echovault/keyspace.go:480.7,487.29 5 0 -github.com/echovault/echovault/echovault/keyspace.go:487.29,489.54 1 0 -github.com/echovault/echovault/echovault/keyspace.go:489.54,491.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:492.10,492.65 1 0 -github.com/echovault/echovault/echovault/keyspace.go:492.65,493.63 1 0 -github.com/echovault/echovault/echovault/keyspace.go:493.63,495.6 1 0 -github.com/echovault/echovault/echovault/keyspace.go:499.4,502.52 3 0 -github.com/echovault/echovault/echovault/keyspace.go:502.52,504.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:506.10,507.13 1 0 -github.com/echovault/echovault/echovault/keyspace.go:516.77,518.57 1 1 -github.com/echovault/echovault/echovault/keyspace.go:518.57,520.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:522.2,527.50 3 1 -github.com/echovault/echovault/echovault/keyspace.go:527.50,529.3 1 0 -github.com/echovault/echovault/echovault/keyspace.go:530.2,537.33 6 1 -github.com/echovault/echovault/echovault/keyspace.go:537.33,538.7 1 0 -github.com/echovault/echovault/echovault/keyspace.go:538.7,542.35 3 0 -github.com/echovault/echovault/echovault/keyspace.go:542.35,544.10 2 0 -github.com/echovault/echovault/echovault/keyspace.go:548.2,551.25 2 1 -github.com/echovault/echovault/echovault/keyspace.go:551.25,552.52 1 0 -github.com/echovault/echovault/echovault/keyspace.go:552.52,553.12 1 0 -github.com/echovault/echovault/echovault/keyspace.go:557.3,557.57 1 0 -github.com/echovault/echovault/echovault/keyspace.go:557.57,559.12 2 0 -github.com/echovault/echovault/echovault/keyspace.go:563.3,565.28 3 0 -github.com/echovault/echovault/echovault/keyspace.go:565.28,566.51 1 0 -github.com/echovault/echovault/echovault/keyspace.go:566.51,568.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:569.9,569.64 1 0 -github.com/echovault/echovault/echovault/keyspace.go:569.64,570.60 1 0 -github.com/echovault/echovault/echovault/keyspace.go:570.60,572.5 1 0 -github.com/echovault/echovault/echovault/keyspace.go:577.2,577.21 1 1 -github.com/echovault/echovault/echovault/keyspace.go:577.21,580.3 1 1 -github.com/echovault/echovault/echovault/keyspace.go:582.2,585.58 2 0 -github.com/echovault/echovault/echovault/keyspace.go:585.58,589.3 2 0 -github.com/echovault/echovault/echovault/keyspace.go:591.2,591.12 1 0 +github.com/echovault/echovault/echovault/keyspace.go:116.74,119.9 3 1 +github.com/echovault/echovault/echovault/keyspace.go:119.9,122.3 2 1 +github.com/echovault/echovault/echovault/keyspace.go:123.2,125.82 2 1 +github.com/echovault/echovault/echovault/keyspace.go:125.82,126.28 1 0 +github.com/echovault/echovault/echovault/keyspace.go:126.28,129.18 2 0 +github.com/echovault/echovault/echovault/keyspace.go:129.18,131.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:132.9,132.64 1 0 +github.com/echovault/echovault/echovault/keyspace.go:132.64,135.18 2 0 +github.com/echovault/echovault/echovault/keyspace.go:135.18,137.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:138.9,138.65 1 0 +github.com/echovault/echovault/echovault/keyspace.go:138.65,143.4 1 0 +github.com/echovault/echovault/echovault/keyspace.go:145.3,145.15 1 0 +github.com/echovault/echovault/echovault/keyspace.go:148.2,148.13 1 1 +github.com/echovault/echovault/echovault/keyspace.go:156.90,157.115 1 1 +github.com/echovault/echovault/echovault/keyspace.go:157.115,159.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:161.2,164.33 3 1 +github.com/echovault/echovault/echovault/keyspace.go:164.33,175.3 5 1 +github.com/echovault/echovault/echovault/keyspace.go:177.2,177.33 1 1 +github.com/echovault/echovault/echovault/keyspace.go:182.80,183.58 1 1 +github.com/echovault/echovault/echovault/keyspace.go:183.58,185.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:186.2,186.32 1 1 +github.com/echovault/echovault/echovault/keyspace.go:193.93,194.115 1 1 +github.com/echovault/echovault/echovault/keyspace.go:194.115,196.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:198.2,204.16 3 1 +github.com/echovault/echovault/echovault/keyspace.go:204.16,206.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:208.2,208.27 1 1 +github.com/echovault/echovault/echovault/keyspace.go:208.27,210.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:212.2,212.12 1 1 +github.com/echovault/echovault/echovault/keyspace.go:217.79,218.58 1 1 +github.com/echovault/echovault/echovault/keyspace.go:218.58,220.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:221.2,221.35 1 1 +github.com/echovault/echovault/echovault/keyspace.go:230.101,238.55 3 1 +github.com/echovault/echovault/echovault/keyspace.go:238.55,240.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:241.2,244.11 2 1 +github.com/echovault/echovault/echovault/keyspace.go:244.11,246.17 2 1 +github.com/echovault/echovault/echovault/keyspace.go:246.17,248.4 1 0 +github.com/echovault/echovault/echovault/keyspace.go:254.70,263.97 4 1 +github.com/echovault/echovault/echovault/keyspace.go:263.97,265.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:273.60,275.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:275.6,276.83 1 0 +github.com/echovault/echovault/echovault/keyspace.go:276.83,278.9 2 0 +github.com/echovault/echovault/echovault/keyspace.go:281.2,282.33 2 0 +github.com/echovault/echovault/echovault/keyspace.go:282.33,284.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:285.2,286.13 2 0 +github.com/echovault/echovault/echovault/keyspace.go:293.75,294.52 1 1 +github.com/echovault/echovault/echovault/keyspace.go:294.52,296.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:299.2,306.9 4 1 +github.com/echovault/echovault/echovault/keyspace.go:307.108,308.36 1 0 +github.com/echovault/echovault/echovault/keyspace.go:309.108,310.36 1 0 +github.com/echovault/echovault/echovault/keyspace.go:315.2,315.12 1 1 +github.com/echovault/echovault/echovault/keyspace.go:320.82,322.83 1 1 +github.com/echovault/echovault/echovault/keyspace.go:322.83,324.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:326.2,326.34 1 1 +github.com/echovault/echovault/echovault/keyspace.go:326.34,328.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:329.2,329.55 1 0 +github.com/echovault/echovault/echovault/keyspace.go:330.28,333.36 3 0 +github.com/echovault/echovault/echovault/keyspace.go:334.28,337.36 3 0 +github.com/echovault/echovault/echovault/keyspace.go:338.29,341.50 3 0 +github.com/echovault/echovault/echovault/keyspace.go:341.50,343.4 1 0 +github.com/echovault/echovault/echovault/keyspace.go:344.29,347.50 3 0 +github.com/echovault/echovault/echovault/keyspace.go:347.50,349.4 1 0 +github.com/echovault/echovault/echovault/keyspace.go:351.2,351.54 1 0 +github.com/echovault/echovault/echovault/keyspace.go:351.54,353.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:354.2,354.12 1 0 +github.com/echovault/echovault/echovault/keyspace.go:358.71,360.34 1 0 +github.com/echovault/echovault/echovault/keyspace.go:360.34,362.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:365.2,368.50 3 0 +github.com/echovault/echovault/echovault/keyspace.go:368.50,370.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:372.2,374.50 3 0 +github.com/echovault/echovault/echovault/keyspace.go:374.50,376.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:380.2,380.9 1 0 +github.com/echovault/echovault/echovault/keyspace.go:381.125,386.7 3 0 +github.com/echovault/echovault/echovault/keyspace.go:386.7,388.40 1 0 +github.com/echovault/echovault/echovault/keyspace.go:388.40,390.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:392.4,393.29 2 0 +github.com/echovault/echovault/echovault/keyspace.go:393.29,395.54 1 0 +github.com/echovault/echovault/echovault/keyspace.go:395.54,397.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:398.10,398.65 1 0 +github.com/echovault/echovault/echovault/keyspace.go:398.65,400.63 1 0 +github.com/echovault/echovault/echovault/keyspace.go:400.63,402.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:406.4,409.52 3 0 +github.com/echovault/echovault/echovault/keyspace.go:409.52,411.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:413.125,418.7 3 0 +github.com/echovault/echovault/echovault/keyspace.go:418.7,420.40 1 0 +github.com/echovault/echovault/echovault/keyspace.go:420.40,422.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:424.4,425.29 2 0 +github.com/echovault/echovault/echovault/keyspace.go:425.29,427.54 1 0 +github.com/echovault/echovault/echovault/keyspace.go:427.54,429.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:430.10,430.65 1 0 +github.com/echovault/echovault/echovault/keyspace.go:430.65,433.63 1 0 +github.com/echovault/echovault/echovault/keyspace.go:433.63,435.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:439.4,442.52 3 0 +github.com/echovault/echovault/echovault/keyspace.go:442.52,444.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:446.105,449.7 1 0 +github.com/echovault/echovault/echovault/keyspace.go:449.7,451.33 1 0 +github.com/echovault/echovault/echovault/keyspace.go:451.33,454.5 2 0 +github.com/echovault/echovault/echovault/keyspace.go:456.4,457.40 2 0 +github.com/echovault/echovault/echovault/keyspace.go:457.40,458.17 1 0 +github.com/echovault/echovault/echovault/keyspace.go:458.17,459.31 1 0 +github.com/echovault/echovault/echovault/keyspace.go:459.31,461.56 1 0 +github.com/echovault/echovault/echovault/keyspace.go:461.56,463.8 1 0 +github.com/echovault/echovault/echovault/keyspace.go:464.12,464.67 1 0 +github.com/echovault/echovault/echovault/keyspace.go:464.67,465.65 1 0 +github.com/echovault/echovault/echovault/keyspace.go:465.65,467.8 1 0 +github.com/echovault/echovault/echovault/keyspace.go:470.6,473.54 3 0 +github.com/echovault/echovault/echovault/keyspace.go:473.54,475.7 1 0 +github.com/echovault/echovault/echovault/keyspace.go:477.5,477.10 1 0 +github.com/echovault/echovault/echovault/keyspace.go:480.106,483.7 1 0 +github.com/echovault/echovault/echovault/keyspace.go:483.7,490.29 5 0 +github.com/echovault/echovault/echovault/keyspace.go:490.29,492.54 1 0 +github.com/echovault/echovault/echovault/keyspace.go:492.54,494.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:495.10,495.65 1 0 +github.com/echovault/echovault/echovault/keyspace.go:495.65,496.63 1 0 +github.com/echovault/echovault/echovault/keyspace.go:496.63,498.6 1 0 +github.com/echovault/echovault/echovault/keyspace.go:502.4,505.52 3 0 +github.com/echovault/echovault/echovault/keyspace.go:505.52,507.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:509.10,510.13 1 0 +github.com/echovault/echovault/echovault/keyspace.go:519.77,521.57 1 1 +github.com/echovault/echovault/echovault/keyspace.go:521.57,523.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:525.2,530.50 3 1 +github.com/echovault/echovault/echovault/keyspace.go:530.50,532.3 1 0 +github.com/echovault/echovault/echovault/keyspace.go:533.2,540.33 6 1 +github.com/echovault/echovault/echovault/keyspace.go:540.33,541.7 1 0 +github.com/echovault/echovault/echovault/keyspace.go:541.7,545.35 3 0 +github.com/echovault/echovault/echovault/keyspace.go:545.35,547.10 2 0 +github.com/echovault/echovault/echovault/keyspace.go:551.2,554.25 2 1 +github.com/echovault/echovault/echovault/keyspace.go:554.25,555.52 1 0 +github.com/echovault/echovault/echovault/keyspace.go:555.52,556.12 1 0 +github.com/echovault/echovault/echovault/keyspace.go:560.3,560.57 1 0 +github.com/echovault/echovault/echovault/keyspace.go:560.57,562.12 2 0 +github.com/echovault/echovault/echovault/keyspace.go:566.3,568.28 3 0 +github.com/echovault/echovault/echovault/keyspace.go:568.28,569.51 1 0 +github.com/echovault/echovault/echovault/keyspace.go:569.51,571.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:572.9,572.64 1 0 +github.com/echovault/echovault/echovault/keyspace.go:572.64,573.60 1 0 +github.com/echovault/echovault/echovault/keyspace.go:573.60,575.5 1 0 +github.com/echovault/echovault/echovault/keyspace.go:580.2,580.21 1 1 +github.com/echovault/echovault/echovault/keyspace.go:580.21,583.3 1 1 +github.com/echovault/echovault/echovault/keyspace.go:585.2,588.58 2 0 +github.com/echovault/echovault/echovault/keyspace.go:588.58,592.3 2 0 +github.com/echovault/echovault/echovault/keyspace.go:594.2,594.12 1 0 github.com/echovault/echovault/echovault/modules.go:27.75,30.42 3 1 github.com/echovault/echovault/echovault/modules.go:30.42,31.46 1 1 github.com/echovault/echovault/echovault/modules.go:31.46,33.4 1 1 diff --git a/echovault/echovault.go b/echovault/echovault.go index a19b902..dd198ed 100644 --- a/echovault/echovault.go +++ b/echovault/echovault.go @@ -61,9 +61,8 @@ type EchoVault struct { // the new number is the new connection's ID. connId atomic.Uint64 - store map[string]internal.KeyData // Data store to hold the keys and their associated data, expiry time, etc. - keyLocks map[string]*sync.RWMutex // Map to hold all the individual key locks. - keyCreationLock *sync.Mutex // The mutex for creating a new key. Only one goroutine should be able to create a key at a time. + storeLock *sync.RWMutex // Global read-write mutex for entire store. + store map[string]internal.KeyData // Data store to hold the keys and their associated data, expiry time, etc. // Holds all the keys that are currently associated with an expiry. keysWithExpiry struct { @@ -128,13 +127,12 @@ func WithConfig(config config.Config) func(echovault *EchoVault) { // This functions accepts the WithContext, WithConfig and WithCommands options. func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { echovault := &EchoVault{ - clock: clock.NewClock(), - context: context.Background(), - config: config.DefaultConfig(), - store: make(map[string]internal.KeyData), - keyLocks: make(map[string]*sync.RWMutex), - keyCreationLock: &sync.Mutex{}, - commandsRWMut: sync.RWMutex{}, + clock: clock.NewClock(), + context: context.Background(), + config: config.DefaultConfig(), + storeLock: &sync.RWMutex{}, + store: make(map[string]internal.KeyData), + commandsRWMut: sync.RWMutex{}, commands: func() []internal.Command { var commands []internal.Command commands = append(commands, acl.Commands()...) @@ -195,10 +193,8 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { echovault.raft = raft.NewRaft(raft.Opts{ Config: echovault.config, GetCommand: echovault.getCommand, - CreateKeyAndLock: echovault.CreateKeyAndLock, SetValue: echovault.SetValue, SetExpiry: echovault.SetExpiry, - KeyUnlock: echovault.KeyUnlock, DeleteKey: echovault.DeleteKey, StartSnapshot: echovault.startSnapshot, FinishSnapshot: echovault.finishSnapshot, @@ -245,14 +241,10 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { }), snapshot.WithSetKeyDataFunc(func(key string, data internal.KeyData) { ctx := context.Background() - if _, err := echovault.CreateKeyAndLock(ctx, key); err != nil { - log.Println(err) - } if err := echovault.SetValue(ctx, key, data.Value); err != nil { log.Println(err) } echovault.SetExpiry(ctx, key, data.ExpireAt, false) - echovault.KeyUnlock(ctx, key) }), ) // Set up standalone AOF engine @@ -273,14 +265,10 @@ func NewEchoVault(options ...func(echovault *EchoVault)) (*EchoVault, error) { }), aof.WithSetKeyDataFunc(func(key string, value internal.KeyData) { ctx := context.Background() - if _, err := echovault.CreateKeyAndLock(ctx, key); err != nil { - log.Println(err) - } if err := echovault.SetValue(ctx, key, value.Value); err != nil { log.Println(err) } echovault.SetExpiry(ctx, key, value.ExpireAt, false) - echovault.KeyUnlock(ctx, key) }), aof.WithHandleCommandFunc(func(command []byte) { _, err := echovault.handleCommand(context.Background(), command, nil, true, false) diff --git a/echovault/echovault_test.go b/echovault/echovault_test.go index 62741fc..e1066e7 100644 --- a/echovault/echovault_test.go +++ b/echovault/echovault_test.go @@ -42,6 +42,8 @@ func getBindAddr() net.IP { return getBindAddrNet(0) } +var setupLock sync.Mutex + func setupServer( serverId string, bootstrapCluster bool, @@ -51,6 +53,9 @@ func setupServer( raftPort, mlPort int, ) (*EchoVault, error) { + setupLock.Lock() + defer setupLock.Unlock() + config := DefaultConfig() config.DataDir = "./testdata" config.BindAddr = bindAddr @@ -181,7 +186,7 @@ func Test_ClusterReplication(t *testing.T) { t.Errorf("could not read data from follower node %d (test %d): %v", j, i, err) } if rd.String() != test.value { - t.Errorf("exptected value \"%s\" for follower node %d (test %d), got \"%s\"", test.value, j, i, rd.String()) + t.Errorf("expected value \"%s\" for follower node %d (test %d), got \"%s\"", test.value, j, i, rd.String()) } } } diff --git a/echovault/keyspace.go b/echovault/keyspace.go index da7d3ed..0fc1b67 100644 --- a/echovault/keyspace.go +++ b/echovault/keyspace.go @@ -26,205 +26,119 @@ import ( "runtime" "slices" "strings" - "sync" "time" ) -// KeyLock tries to acquire the write lock for the specified key. -// If the context passed to the function finishes before the lock is acquired, an error is returned. -// -// If this functions is called on a node in a replication cluster, the key is only locked -// on that particular node. -func (server *EchoVault) KeyLock(ctx context.Context, key string) (bool, error) { - // If context did not set deadline, set the default deadline - var cancelFunc context.CancelFunc - if _, ok := ctx.Deadline(); !ok { - ctx, cancelFunc = context.WithTimeoutCause(ctx, 250*time.Millisecond, fmt.Errorf("timeout for key %s", key)) - defer cancelFunc() - } - // Attempt to acquire the lock until lock is acquired or deadline is reached. - for { - select { - default: - if server.keyLocks[key] == nil { - return false, fmt.Errorf("key %s not found", key) - } - ok := server.keyLocks[key].TryLock() - if ok { - return true, nil - } - case <-ctx.Done(): - return false, context.Cause(ctx) - } +func (server *EchoVault) keysExist(keys []string) map[string]bool { + server.storeLock.RLock() + defer server.storeLock.RUnlock() + + exists := make(map[string]bool, len(keys)) + + for _, key := range keys { + _, ok := server.store[key] + exists[key] = ok } + + return exists } -// KeyUnlock releases the write lock for the specified key. -// -// If this functions is called on a node in a replication cluster, the key is only unlocked -// on that particular node. -func (server *EchoVault) KeyUnlock(_ context.Context, key string) { - if _, ok := server.keyLocks[key]; ok { - server.keyLocks[key].Unlock() - } -} +func (server *EchoVault) getExpiry(key string) time.Time { + server.storeLock.RLock() + defer server.storeLock.RUnlock() -// KeyRLock tries to acquire the read lock for the specified key. -// If the context passed to the function finishes before the lock is acquired, an error is returned. -// -// If this functions is called on a node in a replication cluster, the key is only locked -// on that particular node. -func (server *EchoVault) KeyRLock(ctx context.Context, key string) (bool, error) { - // If context did not set deadline, set the default deadline - var cancelFunc context.CancelFunc - if _, ok := ctx.Deadline(); !ok { - ctx, cancelFunc = context.WithTimeoutCause(ctx, 250*time.Millisecond, fmt.Errorf("timeout for key %s", key)) - defer cancelFunc() - } - // Attempt to acquire the lock until lock is acquired or deadline is reached. - for { - select { - default: - if server.keyLocks[key] == nil { - return false, fmt.Errorf("key %s not found", key) - } - ok := server.keyLocks[key].TryRLock() - if ok { - return true, nil - } - case <-ctx.Done(): - return false, context.Cause(ctx) - } - } -} - -// KeyRUnlock releases the read lock for the specified key. -// -// If this functions is called on a node in a replication cluster, the key is only unlocked -// on that particular node. -func (server *EchoVault) KeyRUnlock(_ context.Context, key string) { - if _, ok := server.keyLocks[key]; ok { - server.keyLocks[key].RUnlock() - } -} - -// KeyExists returns true if the key exists in the store. -// -// If the key is volatile and expired, checking for its existence with KeyExists will trigger a key deletion and -// then return false. If the key is determined to be expired by KeyExists, it will be evicted across the entire -// replication cluster. -func (server *EchoVault) KeyExists(ctx context.Context, key string) bool { entry, ok := server.store[key] if !ok { - return false + return time.Time{} } - if entry.ExpireAt != (time.Time{}) && entry.ExpireAt.Before(server.clock.Now()) { - if !server.isInCluster() { - // If in standalone mode, delete the key directly. - err := server.DeleteKey(ctx, key) - if err != nil { - log.Printf("keyExists: %+v\n", err) - } - } else if server.isInCluster() && server.raft.IsRaftLeader() { - // If we're in a raft cluster, and we're the leader, send command to delete the key in the cluster. - err := server.raftApplyDeleteKey(ctx, key) - if err != nil { - log.Printf("keyExists: %+v\n", err) - } - } else if server.isInCluster() && !server.raft.IsRaftLeader() { - // Forward message to leader to initiate key deletion. - // This is always called regardless of ForwardCommand config value - // because we always want to remove expired keys. - server.memberList.ForwardDeleteKey(ctx, key) + return entry.ExpireAt +} + +func (server *EchoVault) getValues(ctx context.Context, keys []string) map[string]interface{} { + server.storeLock.Lock() + defer server.storeLock.Unlock() + + values := make(map[string]interface{}, len(keys)) + + for _, key := range keys { + entry, ok := server.store[key] + if !ok { + values[key] = nil + continue } - return false - } - - return true -} - -// CreateKeyAndLock creates a new key lock and immediately locks it if the key does not exist. -// If the key exists, the existing key is locked. -// -// If this functions is called on a node in a replication cluster, the key is only created/locked -// on that particular node. -func (server *EchoVault) CreateKeyAndLock(ctx context.Context, key string) (bool, error) { - if internal.IsMaxMemoryExceeded(server.config.MaxMemory) && server.config.EvictionPolicy == constants.NoEviction { - return false, errors.New("max memory reached, key not created") - } - - server.keyCreationLock.Lock() - defer server.keyCreationLock.Unlock() - - if !server.KeyExists(ctx, key) { - // Create Lock - keyLock := &sync.RWMutex{} - keyLock.Lock() - server.keyLocks[key] = keyLock - // Create key entry - server.store[key] = internal.KeyData{ - Value: nil, - ExpireAt: time.Time{}, + if entry.ExpireAt != (time.Time{}) && entry.ExpireAt.Before(server.clock.Now()) { + if !server.isInCluster() { + // If in standalone mode, delete the key directly. + err := server.deleteKey(key) + if err != nil { + log.Printf("keyExists: %+v\n", err) + } + } else if server.isInCluster() && server.raft.IsRaftLeader() { + // If we're in a raft cluster, and we're the leader, send command to delete the key in the cluster. + err := server.raftApplyDeleteKey(ctx, key) + if err != nil { + log.Printf("keyExists: %+v\n", err) + } + } else if server.isInCluster() && !server.raft.IsRaftLeader() { + // Forward message to leader to initiate key deletion. + // This is always called regardless of ForwardCommand config value + // because we always want to remove expired keys. + server.memberList.ForwardDeleteKey(ctx, key) + } + values[key] = nil + continue } - return true, nil + + values[key] = entry.Value } - return server.KeyLock(ctx, key) + // Asynchronously update the keys in the cache. + go func(ctx context.Context, keys []string) { + if err := server.updateKeysInCache(ctx, keys); err != nil { + log.Printf("getValues error: %+v\n", err) + } + }(ctx, keys) + + return values } -// GetValue retrieves the current value at the specified key. -// The key must be read-locked before calling this function. -func (server *EchoVault) GetValue(ctx context.Context, key string) interface{} { - if err := server.updateKeyInCache(ctx, key); err != nil { - log.Printf("GetValue error: %+v\n", err) - } - return server.store[key].Value -} +func (server *EchoVault) setValues(ctx context.Context, entries map[string]interface{}) error { + server.storeLock.Lock() + defer server.storeLock.Unlock() -// SetValue updates the value in the store at the specified key with the given value. -// If we're in not in cluster (i.e. in standalone mode), then the change count is incremented in the snapshot engine. -// This count triggers a snapshot when the threshold is reached. -// The key must be locked prior to calling this function. -func (server *EchoVault) SetValue(ctx context.Context, key string, value interface{}) error { if internal.IsMaxMemoryExceeded(server.config.MaxMemory) && server.config.EvictionPolicy == constants.NoEviction { return errors.New("max memory reached, key value not set") } - server.store[key] = internal.KeyData{ - Value: value, - ExpireAt: server.store[key].ExpireAt, + for key, value := range entries { + server.store[key] = internal.KeyData{ + Value: value, + ExpireAt: server.store[key].ExpireAt, + } + if !server.isInCluster() { + server.snapshotEngine.IncrementChangeCount() + } } - err := server.updateKeyInCache(ctx, key) - if err != nil { - log.Printf("SetValue error: %+v\n", err) - } - - if !server.isInCluster() { - server.snapshotEngine.IncrementChangeCount() - } + // Asynchronously update the keys in the cache. + go func(ctx context.Context, entries map[string]interface{}) { + for key, _ := range entries { + err := server.updateKeysInCache(ctx, []string{key}) + if err != nil { + log.Printf("setValues error: %+v\n", err) + } + } + }(ctx, entries) return nil } -// The GetExpiry function returns the expiry time associated with the provided key. -// The key must be read locked before calling this function. -func (server *EchoVault) GetExpiry(ctx context.Context, key string) time.Time { - if err := server.updateKeyInCache(ctx, key); err != nil { - log.Printf("GetKeyExpiry error: %+v\n", err) - } - return server.store[key].ExpireAt -} +func (server *EchoVault) setExpiry(ctx context.Context, key string, expireAt time.Time, touch bool) { + server.storeLock.Lock() + defer server.storeLock.Unlock() -// The SetExpiry receiver function sets the expiry time of a key. -// The key parameter represents the key whose expiry time is to be set/updated. -// The expireAt parameter is the new expiry time. -// The touch parameter determines whether to update the keys access count on lfu eviction policy, -// or the access time on lru eviction policy. -// The key must be locked prior to calling this function. -func (server *EchoVault) SetExpiry(ctx context.Context, key string, expireAt time.Time, touch bool) { server.store[key] = internal.KeyData{ Value: server.store[key].Value, ExpireAt: expireAt, @@ -239,34 +153,39 @@ func (server *EchoVault) SetExpiry(ctx context.Context, key string, expireAt tim // If touch is true, update the keys status in the cache. if touch { - err := server.updateKeyInCache(ctx, key) - if err != nil { - log.Printf("SetKeyExpiry error: %+v\n", err) - } + go func(ctx context.Context, key string) { + err := server.updateKeysInCache(ctx, []string{key}) + if err != nil { + log.Printf("SetKeyExpiry error: %+v\n", err) + } + }(ctx, key) } } -// RemoveExpiry is called by commands that remove key expiry (e.g. Persist). -// The key must be locked prior ro calling this function. -func (server *EchoVault) RemoveExpiry(_ context.Context, key string) { - // Reset expiry time - server.store[key] = internal.KeyData{ - Value: server.store[key].Value, - ExpireAt: time.Time{}, - } - // Remove key from slice of keys associated with expiry +func (server *EchoVault) deleteKey(key string) error { + // Delete the key from keyLocks and store. + delete(server.store, key) + + // Remove key from slice of keys associated with expiry. server.keysWithExpiry.rwMutex.Lock() defer server.keysWithExpiry.rwMutex.Unlock() server.keysWithExpiry.keys = slices.DeleteFunc(server.keysWithExpiry.keys, func(k string) bool { return k == key }) + + // Remove the key from the cache. + switch { + case slices.Contains([]string{constants.AllKeysLFU, constants.VolatileLFU}, server.config.EvictionPolicy): + server.lfuCache.cache.Delete(key) + case slices.Contains([]string{constants.AllKeysLRU, constants.VolatileLRU}, server.config.EvictionPolicy): + server.lruCache.cache.Delete(key) + } + + // log.Printf("deleted key %s\n", key) // TODO: Uncomment this + + return nil } -// GetState creates a deep copy of the store map. -// It is used to retrieve the current state for persistence but can also be used for other -// functions that require a deep copy of the state. -// The copy only starts when there's no current copy in progress (represented by stateCopyInProgress atomic boolean) -// and when there's no current state mutation in progress (represented by stateMutationInProgress atomic boolean) func (server *EchoVault) getState() map[string]interface{} { // Wait unit there's no state mutation or copy in progress before starting a new copy process. for { @@ -283,70 +202,43 @@ func (server *EchoVault) getState() map[string]interface{} { return data } -// DeleteKey removes the key from store, keyLocks and keyExpiry maps. -// -// If this functions is called on a node in a replication cluster, the key is only deleted -// on that particular node. -func (server *EchoVault) DeleteKey(ctx context.Context, key string) error { - if _, err := server.KeyLock(ctx, key); err != nil { - return fmt.Errorf("deleteKey error: %+v", err) - } - - // Remove key expiry. - server.RemoveExpiry(ctx, key) - - // Delete the key from keyLocks and store. - delete(server.keyLocks, key) - delete(server.store, key) - - // Remove the key from the cache. - switch { - case slices.Contains([]string{constants.AllKeysLFU, constants.VolatileLFU}, server.config.EvictionPolicy): - server.lfuCache.cache.Delete(key) - case slices.Contains([]string{constants.AllKeysLRU, constants.VolatileLRU}, server.config.EvictionPolicy): - server.lruCache.cache.Delete(key) - } - - // log.Printf("deleted key %s\n", key) // TODO: Uncomment this - - return nil -} - -// updateKeyInCache updates either the key access count or the most recent access time in the cache +// updateKeysInCache updates either the key access count or the most recent access time in the cache // depending on whether an LFU or LRU strategy was used. -func (server *EchoVault) updateKeyInCache(ctx context.Context, key string) error { - // Only update cache when in standalone mode or when raft leader - if server.isInCluster() || (server.isInCluster() && !server.raft.IsRaftLeader()) { - return nil - } - // If max memory is 0, there's no max so no need to update caches - if server.config.MaxMemory == 0 { - return nil - } - switch strings.ToLower(server.config.EvictionPolicy) { - case constants.AllKeysLFU: - server.lfuCache.mutex.Lock() - defer server.lfuCache.mutex.Unlock() - server.lfuCache.cache.Update(key) - case constants.AllKeysLRU: - server.lruCache.mutex.Lock() - defer server.lruCache.mutex.Unlock() - server.lruCache.cache.Update(key) - case constants.VolatileLFU: - server.lfuCache.mutex.Lock() - defer server.lfuCache.mutex.Unlock() - if server.store[key].ExpireAt != (time.Time{}) { +func (server *EchoVault) updateKeysInCache(ctx context.Context, keys []string) error { + for _, key := range keys { + // Only update cache when in standalone mode or when raft leader. + if server.isInCluster() || (server.isInCluster() && !server.raft.IsRaftLeader()) { + return nil + } + // If max memory is 0, there's no max so no need to update caches. + if server.config.MaxMemory == 0 { + return nil + } + switch strings.ToLower(server.config.EvictionPolicy) { + case constants.AllKeysLFU: + server.lfuCache.mutex.Lock() server.lfuCache.cache.Update(key) - } - case constants.VolatileLRU: - server.lruCache.mutex.Lock() - defer server.lruCache.mutex.Unlock() - if server.store[key].ExpireAt != (time.Time{}) { + server.lfuCache.mutex.Unlock() + case constants.AllKeysLRU: + server.lruCache.mutex.Lock() server.lruCache.cache.Update(key) + server.lruCache.mutex.Unlock() + case constants.VolatileLFU: + server.lfuCache.mutex.Lock() + if server.store[key].ExpireAt != (time.Time{}) { + server.lfuCache.cache.Update(key) + } + server.lfuCache.mutex.Unlock() + case constants.VolatileLRU: + server.lruCache.mutex.Lock() + if server.store[key].ExpireAt != (time.Time{}) { + server.lruCache.cache.Update(key) + } + server.lruCache.mutex.Unlock() + } + if err := server.adjustMemoryUsage(ctx); err != nil { + return fmt.Errorf("updateKeysInCache: %+v", err) } - } - if err := server.adjustMemoryUsage(ctx); err != nil { - return fmt.Errorf("updateKeyInCache: %+v", err) } return nil } @@ -374,6 +266,8 @@ func (server *EchoVault) adjustMemoryUsage(ctx context.Context) error { // We've done a GC, but we're still at or above the max memory limit. // Start a loop that evicts keys until either the heap is empty or // we're below the max memory limit. + server.storeLock.Lock() + defer server.storeLock.Unlock() switch { case slices.Contains([]string{constants.AllKeysLFU, constants.VolatileLFU}, strings.ToLower(server.config.EvictionPolicy)): // Remove keys from LFU cache until we're below the max memory limit or @@ -389,7 +283,7 @@ func (server *EchoVault) adjustMemoryUsage(ctx context.Context) error { key := heap.Pop(&server.lfuCache.cache).(string) if !server.isInCluster() { // If in standalone mode, directly delete the key - if err := server.DeleteKey(ctx, key); err != nil { + if err := server.deleteKey(key); err != nil { return fmt.Errorf("adjustMemoryUsage -> LFU cache eviction: %+v", err) } } else if server.isInCluster() && server.raft.IsRaftLeader() { @@ -421,7 +315,7 @@ func (server *EchoVault) adjustMemoryUsage(ctx context.Context) error { key := heap.Pop(&server.lruCache.cache).(string) if !server.isInCluster() { // If in standalone mode, directly delete the key. - if err := server.DeleteKey(ctx, key); err != nil { + if err := server.deleteKey(key); err != nil { return fmt.Errorf("adjustMemoryUsage -> LRU cache eviction: %+v", err) } } else if server.isInCluster() && server.raft.IsRaftLeader() { @@ -444,18 +338,20 @@ func (server *EchoVault) adjustMemoryUsage(ctx context.Context) error { // Remove random keys until we're below the max memory limit // or there are no more keys remaining. for { + server.storeLock.Lock() // If there are no keys, return error - if len(server.keyLocks) == 0 { + if len(server.store) == 0 { err := errors.New("no keys to evict") + server.storeLock.Unlock() return fmt.Errorf("adjustMemoryUsage -> all keys random: %+v", err) } // Get random key - idx := rand.Intn(len(server.keyLocks)) - for key, _ := range server.keyLocks { + idx := rand.Intn(len(server.store)) + for key, _ := range server.store { if idx == 0 { if !server.isInCluster() { // If in standalone mode, directly delete the key - if err := server.DeleteKey(ctx, key); err != nil { + if err := server.deleteKey(key); err != nil { return fmt.Errorf("adjustMemoryUsage -> all keys random: %+v", err) } } else if server.isInCluster() && server.raft.IsRaftLeader() { @@ -486,7 +382,7 @@ func (server *EchoVault) adjustMemoryUsage(ctx context.Context) error { if !server.isInCluster() { // If in standalone mode, directly delete the key - if err := server.DeleteKey(ctx, key); err != nil { + if err := server.deleteKey(key); err != nil { return fmt.Errorf("adjustMemoryUsage -> volatile keys random: %+v", err) } } else if server.isInCluster() && server.raft.IsRaftLeader() { @@ -548,22 +444,13 @@ func (server *EchoVault) evictKeysWithExpiredTTL(ctx context.Context) error { server.keysWithExpiry.rwMutex.RUnlock() // Loop through the keys and delete them if they're expired + server.storeLock.Lock() + defer server.storeLock.Unlock() for _, k := range keys { - if _, err := server.KeyRLock(ctx, k); err != nil { - continue - } - - // If the current key is not expired, skip to the next key - if server.store[k].ExpireAt.After(server.clock.Now()) { - server.KeyRUnlock(ctx, k) - continue - } - // Delete the expired key deletedCount += 1 - server.KeyRUnlock(ctx, k) if !server.isInCluster() { - if err := server.DeleteKey(ctx, k); err != nil { + if err := server.deleteKey(k); err != nil { return fmt.Errorf("evictKeysWithExpiredTTL -> standalone delete: %+v", err) } } else if server.isInCluster() && server.raft.IsRaftLeader() { diff --git a/echovault/modules.go b/echovault/modules.go index daf5654..8a456de 100644 --- a/echovault/modules.go +++ b/echovault/modules.go @@ -40,17 +40,11 @@ func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, Context: ctx, Command: cmd, Connection: conn, - KeyExists: server.KeyExists, - CreateKeyAndLock: server.CreateKeyAndLock, - KeyLock: server.KeyLock, - KeyRLock: server.KeyRLock, - KeyUnlock: server.KeyUnlock, - KeyRUnlock: server.KeyRUnlock, - GetValue: server.GetValue, - SetValue: server.SetValue, - GetExpiry: server.GetExpiry, - SetExpiry: server.SetExpiry, - DeleteKey: server.DeleteKey, + KeysExist: server.keysExist, + GetExpiry: server.getExpiry, + GetValues: server.getValues, + SetValues: server.setValues, + SetExpiry: server.setExpiry, TakeSnapshot: server.takeSnapshot, GetLatestSnapshotTime: server.getLatestSnapshotTime, RewriteAOF: server.rewriteAOF, @@ -61,6 +55,11 @@ func (server *EchoVault) getHandlerFuncParams(ctx context.Context, cmd []string, GetPubSub: server.getPubSub, GetACL: server.getACL, GetAllCommands: server.getCommands, + DeleteKey: func(key string) error { + server.storeLock.Lock() + defer server.storeLock.Unlock() + return server.deleteKey(key) + }, } } diff --git a/internal/types.go b/internal/types.go index d17e5c7..4402acd 100644 --- a/internal/types.go +++ b/internal/types.go @@ -59,18 +59,12 @@ type HandlerFuncParams struct { Context context.Context Command []string Connection *net.Conn - KeyLock func(ctx context.Context, key string) (bool, error) - KeyUnlock func(ctx context.Context, key string) - KeyRLock func(ctx context.Context, key string) (bool, error) - KeyRUnlock func(ctx context.Context, key string) - KeyExists func(ctx context.Context, key string) bool - CreateKeyAndLock func(ctx context.Context, key string) (bool, error) - GetValue func(ctx context.Context, key string) interface{} - SetValue func(ctx context.Context, key string, value interface{}) error - GetExpiry func(ctx context.Context, key string) time.Time + KeysExist func(keys []string) map[string]bool + GetExpiry func(key string) time.Time + DeleteKey func(key string) error + GetValues func(ctx context.Context, keys []string) map[string]interface{} + SetValues func(ctx context.Context, entries map[string]interface{}) error SetExpiry func(ctx context.Context, key string, expire time.Time, touch bool) - RemoveExpiry func(ctx context.Context, key string) - DeleteKey func(ctx context.Context, key string) error GetClock func() clock.Clock GetAllCommands func() []Command GetACL func() interface{}