Skip to content

Commit 8c2ba99

Browse files
committed
Concurrency for traversal
1 parent af2a284 commit 8c2ba99

File tree

4 files changed

+50
-30
lines changed

4 files changed

+50
-30
lines changed

Diff for: cli/command.go

+23-8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli
33
import (
44
"path/filepath"
55
"strings"
6+
"sync"
67

78
"github.com/fishi0x01/vsh/client"
89
"github.com/fishi0x01/vsh/log"
@@ -61,17 +62,31 @@ func cmdPath(pwd string, arg string) (result string) {
6162
return result
6263
}
6364

65+
var numWorkers = 5
66+
6467
func runCommandWithTraverseTwoPaths(client *client.Client, source string, target string, f func(string, string) error) {
68+
c := make(chan string, numWorkers)
6569
source = filepath.Clean(source) // remove potential trailing '/'
66-
for _, path := range client.Traverse(source) {
67-
target := strings.Replace(path, source, target, 1)
68-
err := f(path, target)
69-
if err != nil {
70-
return
71-
}
70+
go client.Traverse(source, c)
71+
var wg sync.WaitGroup
72+
for t := 0; t < numWorkers; t++ {
73+
wg.Add(1)
74+
go func() {
75+
defer wg.Done()
76+
for {
77+
path, ok := <-c
78+
if !ok {
79+
return
80+
}
81+
target := strings.Replace(path, source, target, 1)
82+
err := f(path, target)
83+
if err != nil {
84+
return
85+
}
86+
}
87+
}()
7288
}
73-
74-
return
89+
wg.Wait()
7590
}
7691

7792
func transportSecrets(c *client.Client, source string, target string, transport func(string, string) error) int {

Diff for: cli/rm.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ func (cmd *RemoveCommand) Run() int {
7272
case client.LEAF:
7373
cmd.removeSecret(newPwd)
7474
case client.NODE:
75-
for _, path := range cmd.client.Traverse(newPwd) {
75+
c := make(chan string, 10)
76+
go cmd.client.Traverse(newPwd, c)
77+
for path := range c {
7678
err := cmd.removeSecret(path)
7779
if err != nil {
7880
return 1

Diff for: client/client.go

+18-12
Original file line numberDiff line numberDiff line change
@@ -153,30 +153,36 @@ func (client *Client) GetType(absolutePath string) (kind PathKind) {
153153
return kind
154154
}
155155

156-
// Traverse traverses given absolutePath via DFS and returns sub-paths in array
157-
func (client *Client) Traverse(absolutePath string) (paths []string) {
156+
// Traverse traverses given absolutePath via DFS and pushes paths to given channel
157+
func (client *Client) Traverse(absolutePath string, c chan<- string) {
158+
defer close(c)
158159
if client.isTopLevelPath(absolutePath) {
159-
paths = client.topLevelTraverse()
160+
client.topLevelTraverse(c)
160161
} else {
161-
paths = client.lowLevelTraverse(normalizedVaultPath(absolutePath))
162+
client.lowLevelTraverse(normalizedVaultPath(absolutePath), c)
162163
}
163-
164-
return paths
165164
}
166165

167166
// SubpathsForPath will return an array of absolute paths at or below path
168-
func (client *Client) SubpathsForPath(path string) (filePaths []string, err error) {
167+
func (client *Client) SubpathsForPath(path string) (result []string, err error) {
169168
switch t := client.GetType(path); t {
170169
case LEAF:
171-
filePaths = append(filePaths, filepath.Clean(path))
170+
result = []string{filepath.Clean(path)}
172171
case NODE:
173-
for _, traversedPath := range client.Traverse(path) {
174-
filePaths = append(filePaths, traversedPath)
172+
c := make(chan string, 10)
173+
go client.Traverse(path, c)
174+
// TODO: this is currently fully sequential to keep old behavior
175+
for {
176+
p, ok := <-c
177+
if !ok {
178+
break
179+
}
180+
result = append(result, p)
175181
}
176182
default:
177-
return filePaths, fmt.Errorf("Not a valid path for operation: %s", path)
183+
err = fmt.Errorf("Not a valid path for operation: %s", path)
178184
}
179-
return filePaths, nil
185+
return result, err
180186
}
181187

182188
// ClearCache clears the list cache

Diff for: client/traverse.go

+6-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ import (
55
"strings"
66
)
77

8-
func (client *Client) topLevelTraverse() (result []string) {
8+
func (client *Client) topLevelTraverse(c chan<- string) {
99
for k := range client.KVBackends {
10-
result = append(result, k)
10+
c <- k
1111
}
12-
13-
return result
1412
}
1513

16-
func (client *Client) lowLevelTraverse(path string) (result []string) {
14+
func (client *Client) lowLevelTraverse(path string, c chan<- string) {
1715
s, err := client.cache.List(client.getKVMetaDataPath(path))
1816
if err != nil {
1917
log.AppTrace("%+v", err)
@@ -27,17 +25,16 @@ func (client *Client) lowLevelTraverse(path string) (result []string) {
2725
// prevent ambiguous dir/file to be added twice
2826
if strings.HasSuffix(val, "/") {
2927
// dir
30-
result = append(result, client.lowLevelTraverse(path+"/"+val)...)
28+
client.lowLevelTraverse(path+"/"+val, c)
3129
} else {
3230
// file
3331
leaf := strings.ReplaceAll("/"+path+"/"+val, "//", "/")
34-
result = append(result, leaf)
32+
c <- leaf
3533
}
3634
}
3735
}
3836
} else {
3937
leaf := strings.ReplaceAll("/"+path, "//", "/")
40-
result = append(result, leaf)
38+
c <- leaf
4139
}
42-
return result
4340
}

0 commit comments

Comments
 (0)