Skip to content

Commit a1e4e80

Browse files
authored
update statediff algorithm for wavesrv / remote instances (#530)
* remote statemap from waveshell server (diff against initial state) * move ShellStatePtr from sstore to packet so it can be passed over the wire * add finalstatebaseptr to cmddone * much improved diff computation code on wavesrv side * fix displayname -- now using hash * add comments, change a couple msh.WriteToPtyBuffer calls to log.Printfs
1 parent 5c85b2b commit a1e4e80

12 files changed

Lines changed: 182 additions & 108 deletions

File tree

waveshell/pkg/packet/packet.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -743,13 +743,14 @@ func MakeCmdFinalPacket(ck base.CommandKey) *CmdFinalPacketType {
743743
}
744744

745745
type CmdDonePacketType struct {
746-
Type string `json:"type"`
747-
Ts int64 `json:"ts"`
748-
CK base.CommandKey `json:"ck"`
749-
ExitCode int `json:"exitcode"`
750-
DurationMs int64 `json:"durationms"`
751-
FinalState *ShellState `json:"finalstate,omitempty"`
752-
FinalStateDiff *ShellStateDiff `json:"finalstatediff,omitempty"`
746+
Type string `json:"type"`
747+
Ts int64 `json:"ts"`
748+
CK base.CommandKey `json:"ck"`
749+
ExitCode int `json:"exitcode"`
750+
DurationMs int64 `json:"durationms"`
751+
FinalState *ShellState `json:"finalstate,omitempty"`
752+
FinalStateDiff *ShellStateDiff `json:"finalstatediff,omitempty"`
753+
FinalStateBasePtr *ShellStatePtr `json:"finalstatebaseptr,omitempty"`
753754
}
754755

755756
func (*CmdDonePacketType) GetType() string {
@@ -814,10 +815,10 @@ type RunPacketType struct {
814815
Type string `json:"type"`
815816
ReqId string `json:"reqid"`
816817
CK base.CommandKey `json:"ck"`
817-
ShellType string `json:"shelltype"` // new in v0.6.0 (either "bash" or "zsh") (set by remote.go)
818+
ShellType string `json:"shelltype"` // added in Wave v0.6.0 (either "bash" or "zsh") (set by remote.go)
818819
Command string `json:"command"`
819820
State *ShellState `json:"state,omitempty"`
820-
StateDiff *ShellStateDiff `json:"statediff,omitempty"`
821+
StatePtr *ShellStatePtr `json:"stateptr,omitempty"` // added in Wave v0.7.2
821822
StateComplete bool `json:"statecomplete,omitempty"` // set to true if state is complete (the default env should not be set)
822823
UsePty bool `json:"usepty,omitempty"`
823824
TermOpts *TermOpts `json:"termopts,omitempty"`

waveshell/pkg/packet/shellstate.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ type ShellState struct {
4040
HashVal string `json:"-"`
4141
}
4242

43+
type ShellStatePtr struct {
44+
BaseHash string `json:"basehash"`
45+
DiffHashArr []string `json:"diffhasharr,omitempty"`
46+
}
47+
48+
func (ssptr *ShellStatePtr) IsEmpty() bool {
49+
if ssptr == nil || ssptr.BaseHash == "" {
50+
return true
51+
}
52+
return false
53+
}
54+
4355
func (state ShellState) ApproximateSize() int64 {
4456
return int64(len(state.Version) + len(state.Cwd) + len(state.ShellVars) + len(state.Aliases) + len(state.Funcs) + len(state.Error))
4557
}

waveshell/pkg/server/server.go

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ type MServer struct {
5050
Sender *packet.PacketSender
5151
ClientMap map[base.CommandKey]*shexec.ClientProc
5252
Debug bool
53-
StateMap *ShellStateMap
5453
WriteErrorCh chan bool // closed if there is a I/O write error
5554
WriteErrorChOnce *sync.Once
5655
Done bool
@@ -338,11 +337,6 @@ func (m *MServer) reinit(reqId string, shellType string) {
338337
m.Sender.SendErrorResponse(reqId, fmt.Errorf("error initializing shell: %w", err))
339338
return
340339
}
341-
err = m.StateMap.SetCurrentState(ssPk.State.GetShellType(), ssPk.State)
342-
if err != nil {
343-
m.Sender.SendErrorResponse(reqId, fmt.Errorf("error setting current state: %w", err))
344-
return
345-
}
346340
ssPk.RespId = reqId
347341
m.Sender.SendPacket(ssPk)
348342
}
@@ -710,33 +704,30 @@ func (m *MServer) ProcessRpcPacket(pk packet.RpcPacketType) {
710704
m.Sender.SendErrorResponse(reqId, fmt.Errorf("invalid rpc type '%s'", pk.GetType()))
711705
}
712706

713-
func (m *MServer) clientPacketCallback(shellType string, pk packet.PacketType) {
707+
func (m *MServer) clientPacketCallback(shellType string, pk packet.PacketType, runPk *packet.RunPacketType) {
714708
if pk.GetType() != packet.CmdDonePacketStr {
715709
return
716710
}
717711
donePk := pk.(*packet.CmdDonePacketType)
718712
if donePk.FinalState == nil {
719713
return
720714
}
721-
stateHash, curState := m.StateMap.GetCurrentState(shellType)
722-
if curState == nil {
715+
initialState := runPk.State
716+
if initialState == nil {
723717
return
724718
}
725-
sapi, err := shellapi.MakeShellApi(curState.GetShellType())
719+
initialStateHash := initialState.GetHashVal(false)
720+
sapi, err := shellapi.MakeShellApi(initialState.GetShellType())
726721
if err != nil {
727722
return
728723
}
729-
diff, err := sapi.MakeShellStateDiff(curState, stateHash, donePk.FinalState)
724+
diff, err := sapi.MakeShellStateDiff(initialState, initialStateHash, donePk.FinalState)
730725
if err != nil {
731726
return
732727
}
733728
donePk.FinalState = nil
734729
donePk.FinalStateDiff = diff
735-
}
736-
737-
func (m *MServer) isShellInitialized(shellType string) bool {
738-
_, curState := m.StateMap.GetCurrentState(shellType)
739-
return curState != nil
730+
donePk.FinalStateBasePtr = runPk.StatePtr
740731
}
741732

742733
func (m *MServer) runCommand(runPacket *packet.RunPacketType) {
@@ -786,7 +777,7 @@ func (m *MServer) runCommand(runPacket *packet.RunPacketType) {
786777
}()
787778
shexec.SendRunPacketAndRunData(context.Background(), cproc.Input, runPacket)
788779
cproc.ProxySingleOutput(runPacket.CK, m.Sender, func(pk packet.PacketType) {
789-
m.clientPacketCallback(runPacket.ShellType, pk)
780+
m.clientPacketCallback(runPacket.ShellType, pk, runPacket)
790781
})
791782
}()
792783
}
@@ -849,7 +840,6 @@ func RunServer() (int, error) {
849840
server := &MServer{
850841
Lock: &sync.Mutex{},
851842
ClientMap: make(map[base.CommandKey]*shexec.ClientProc),
852-
StateMap: MakeShellStateMap(),
853843
Debug: debug,
854844
WriteErrorCh: make(chan bool),
855845
WriteErrorChOnce: &sync.Once{},

waveshell/pkg/shellapi/shellapi.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ type ShellStateOutput struct {
6363
Error string
6464
}
6565

66+
// some timing info
67+
// MakeShellStateDiff takes ~1ms to run (even on a large diff)
68+
6669
type ShellApi interface {
6770
GetShellType() string
6871
MakeExitTrap(fdNum int) (string, []byte)

waveshell/pkg/statediff/linediff.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ func readEncodedStringArray(buf *bytes.Buffer) ([]string, error) {
186186

187187
func (rtn *LineDiffType) Decode(diffBytes []byte) error {
188188
rtn.Clear()
189+
if len(diffBytes) == 0 {
190+
return nil
191+
}
189192
r := bytes.NewBuffer(diffBytes)
190193
version, err := binary.ReadUvarint(r)
191194
if err != nil {

waveshell/pkg/statediff/mapdiff.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func (diff *MapDiffType) Clear() {
2929
}
3030

3131
func (diff MapDiffType) Dump() {
32-
fmt.Printf("VAR-DIFF\n")
32+
fmt.Printf("VAR-DIFF +%d -%d\n", len(diff.ToAdd), len(diff.ToRemove))
3333
for name, val := range diff.ToAdd {
3434
fmt.Printf(" add[%s] %s\n", name, val)
3535
}
@@ -111,6 +111,9 @@ func (diff MapDiffType) Encode() []byte {
111111

112112
func (diff *MapDiffType) Decode(diffBytes []byte) error {
113113
diff.Clear()
114+
if len(diffBytes) == 0 {
115+
return nil
116+
}
114117
r := bytes.NewBuffer(diffBytes)
115118
version, err := binpack.UnpackUInt(r)
116119
if err != nil {

wavesrv/pkg/cmdrunner/cmdrunner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3862,7 +3862,7 @@ func doAsyncResetCommand(msh *remote.MShellProc, opts connectOptsType, cmd *ssto
38623862
rtnErr = err
38633863
return
38643864
}
3865-
newStatePtr := sstore.ShellStatePtr{
3865+
newStatePtr := packet.ShellStatePtr{
38663866
BaseHash: ssPk.State.GetHashVal(false),
38673867
}
38683868
if opts.Verbose && origStatePtr != nil {

wavesrv/pkg/cmdrunner/resolver.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
"github.com/google/uuid"
15+
"github.com/wavetermdev/waveterm/waveshell/pkg/packet"
1516
"github.com/wavetermdev/waveterm/wavesrv/pkg/remote"
1617
"github.com/wavetermdev/waveterm/wavesrv/pkg/scpacket"
1718
"github.com/wavetermdev/waveterm/wavesrv/pkg/sstore"
@@ -42,7 +43,7 @@ type ResolvedRemote struct {
4243
RState remote.RemoteRuntimeState
4344
RemoteCopy *sstore.RemoteType
4445
ShellType string // default remote shell preference
45-
StatePtr *sstore.ShellStatePtr
46+
StatePtr *packet.ShellStatePtr
4647
FeState map[string]string
4748
}
4849

@@ -491,7 +492,7 @@ func ResolveRemoteFromPtr(ctx context.Context, rptr *sstore.RemotePtrType, sessi
491492
rtn.StatePtr = nil
492493
rtn.FeState = nil
493494
} else {
494-
rtn.StatePtr = &sstore.ShellStatePtr{BaseHash: ri.StateBaseHash, DiffHashArr: ri.StateDiffHashArr}
495+
rtn.StatePtr = &packet.ShellStatePtr{BaseHash: ri.StateBaseHash, DiffHashArr: ri.StateDiffHashArr}
495496
rtn.FeState = ri.FeState
496497
rtn.ShellType = ri.ShellType
497498
}

0 commit comments

Comments
 (0)