Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 898dc43

Browse files
committed
ssh: support multiple connections for one transfer
Since we currently support multiple connections for HTTPS, let's also add multiple connections for pure SSH connections. For now, we spawn a whole new connection, but in the future we'll support using OpenSSH's ControlMaster flag. Introduce several new functions to create SSH connections and adjust the number of connection being used.
1 parent 594f8e3 commit 898dc43

2 files changed

Lines changed: 83 additions & 12 deletions

File tree

ssh/connection.go

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
11
package ssh
22

33
import (
4+
"sync"
5+
46
"github.com/git-lfs/git-lfs/config"
57
"github.com/git-lfs/git-lfs/subprocess"
68
"github.com/git-lfs/pktline"
79
)
810

911
type SSHTransfer struct {
10-
conn *PktlineConnection
12+
lock *sync.RWMutex
13+
conn []*PktlineConnection
14+
osEnv config.Environment
15+
gitEnv config.Environment
16+
meta *SSHMetadata
17+
operation string
1118
}
1219

1320
func NewSSHTransfer(osEnv config.Environment, gitEnv config.Environment, meta *SSHMetadata, operation string) (*SSHTransfer, error) {
21+
conn, err := startConnection(osEnv, gitEnv, meta, operation)
22+
if err != nil {
23+
return nil, err
24+
}
25+
return &SSHTransfer{
26+
lock: &sync.RWMutex{},
27+
osEnv: osEnv,
28+
gitEnv: gitEnv,
29+
meta: meta,
30+
operation: operation,
31+
conn: []*PktlineConnection{conn},
32+
}, nil
33+
}
34+
35+
func startConnection(osEnv config.Environment, gitEnv config.Environment, meta *SSHMetadata, operation string) (*PktlineConnection, error) {
1436
exe, args := GetLFSExeAndArgs(osEnv, gitEnv, meta, "git-lfs-transfer", operation)
1537
cmd := subprocess.ExecCommand(exe, args...)
1638
r, err := cmd.StdoutPipe()
@@ -37,14 +59,63 @@ func NewSSHTransfer(osEnv config.Environment, gitEnv config.Environment, meta *S
3759
pl: pl,
3860
}
3961
err = conn.Start()
40-
if err != nil {
41-
return nil, err
62+
return conn, err
63+
}
64+
65+
// Connection returns the nth connection (starting from 0) in this transfer
66+
// instance or nil if there is no such item.
67+
func (tr *SSHTransfer) Connection(n int) *PktlineConnection {
68+
tr.lock.RLock()
69+
defer tr.lock.RUnlock()
70+
if n >= len(tr.conn) {
71+
return nil
4272
}
43-
return &SSHTransfer{
44-
conn: conn,
45-
}, nil
73+
return tr.conn[n]
4674
}
4775

48-
func (tr *SSHTransfer) Connection() *PktlineConnection {
49-
return tr.conn
76+
// ConnectionCount returns the number of connections this object has.
77+
func (tr *SSHTransfer) ConnectionCount() int {
78+
tr.lock.RLock()
79+
defer tr.lock.RUnlock()
80+
return len(tr.conn)
81+
}
82+
83+
// SetConnectionCount sets the number of connections to the specified number.
84+
func (tr *SSHTransfer) SetConnectionCount(n int) error {
85+
tr.lock.Lock()
86+
defer tr.lock.Unlock()
87+
return tr.setConnectionCount(n)
88+
}
89+
90+
// SetConnectionCountAtLeast sets the number of connections to be not less than
91+
// the specified number.
92+
func (tr *SSHTransfer) SetConnectionCountAtLeast(n int) error {
93+
tr.lock.Lock()
94+
defer tr.lock.Unlock()
95+
count := len(tr.conn)
96+
if n <= count {
97+
return nil
98+
}
99+
return tr.setConnectionCount(n)
100+
}
101+
102+
func (tr *SSHTransfer) setConnectionCount(n int) error {
103+
count := len(tr.conn)
104+
if n < count {
105+
for _, item := range tr.conn[n:count] {
106+
if err := item.End(); err != nil {
107+
return err
108+
}
109+
}
110+
tr.conn = tr.conn[0:n]
111+
} else if n > count {
112+
for i := count; i < n; i++ {
113+
conn, err := startConnection(tr.osEnv, tr.gitEnv, tr.meta, tr.operation)
114+
if err != nil {
115+
return err
116+
}
117+
tr.conn = append(tr.conn, conn)
118+
}
119+
}
120+
return nil
50121
}

tq/ssh.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type SSHBatchClient struct {
2525
}
2626

2727
func (a *SSHBatchClient) batchInternal(args []string, batchLines []string) (int, []string, error) {
28-
conn := a.transfer.Connection()
28+
conn := a.transfer.Connection(0)
2929
conn.Lock()
3030
defer conn.Unlock()
3131
err := conn.SendMessageWithLines("batch", args, batchLines)
@@ -196,7 +196,7 @@ func (a *SSHAdapter) download(t *Transfer, cb ProgressCallback) error {
196196

197197
// doDownload starts a download. f is expected to be an existing file open in RW mode
198198
func (a *SSHAdapter) doDownload(t *Transfer, f *os.File, cb ProgressCallback) error {
199-
conn := a.transfer.Connection()
199+
conn := a.transfer.Connection(0)
200200
args := a.argumentsForTransfer(t, "download")
201201
conn.Lock()
202202
defer conn.Unlock()
@@ -266,7 +266,7 @@ func (a *SSHAdapter) doDownload(t *Transfer, f *os.File, cb ProgressCallback) er
266266
}
267267

268268
func (a *SSHAdapter) verifyUpload(t *Transfer) error {
269-
conn := a.transfer.Connection()
269+
conn := a.transfer.Connection(0)
270270
args := a.argumentsForTransfer(t, "upload")
271271
conn.Lock()
272272
defer conn.Unlock()
@@ -288,7 +288,7 @@ func (a *SSHAdapter) verifyUpload(t *Transfer) error {
288288
}
289289

290290
func (a *SSHAdapter) doUpload(t *Transfer, f *os.File, cb ProgressCallback) (int, []string, []string, error) {
291-
conn := a.transfer.Connection()
291+
conn := a.transfer.Connection(0)
292292
args := a.argumentsForTransfer(t, "upload")
293293

294294
// Ensure progress callbacks made while uploading

0 commit comments

Comments
 (0)