@ -118,14 +118,21 @@ func (c *commandFsMetaSave) Do(args []string, commandEnv *CommandEnv, writer io.
outputChan <- bytes
outputChan <- bytes
return nil
return nil
} , func ( outputChan chan interface { } ) {
} , func ( outputChan chan interface { } ) error {
sizeBuf := make ( [ ] byte , 4 )
sizeBuf := make ( [ ] byte , 4 )
for item := range outputChan {
for item := range outputChan {
b := item . ( [ ] byte )
b := item . ( [ ] byte )
util . Uint32toBytes ( sizeBuf , uint32 ( len ( b ) ) )
util . Uint32toBytes ( sizeBuf , uint32 ( len ( b ) ) )
dst . Write ( sizeBuf )
dst . Write ( b )
_ , err := dst . Write ( sizeBuf )
if err != nil {
return err
}
_ , err = dst . Write ( b )
if err != nil {
return err
}
}
}
return nil
} )
} )
if err == nil {
if err == nil {
@ -136,17 +143,21 @@ func (c *commandFsMetaSave) Do(args []string, commandEnv *CommandEnv, writer io.
}
}
func doTraverseBfsAndSaving ( filerClient filer_pb . FilerClient , writer io . Writer , path string , verbose bool , genFn func ( entry * filer_pb . FullEntry , outputChan chan interface { } ) error , saveFn func ( outputChan chan interface { } ) ) error {
func doTraverseBfsAndSaving ( filerClient filer_pb . FilerClient , writer io . Writer , path string , verbose bool , genFn func ( entry * filer_pb . FullEntry , outputChan chan interface { } ) error , saveFn func ( outputChan chan interface { } ) error ) error {
var wg sync . WaitGroup
var wg sync . WaitGroup
wg . Add ( 1 )
wg . Add ( 1 )
outputChan := make ( chan interface { } , 1024 )
outputChan := make ( chan interface { } , 1024 )
saveErrChan := make ( chan error , 1 )
go func ( ) {
go func ( ) {
saveFn ( outputChan )
saveErrChan <- saveFn ( outputChan )
wg . Done ( )
wg . Done ( )
} ( )
} ( )
var dirCount , fileCount uint64
var dirCount , fileCount uint64
var once sync . Once
var firstErr error
var hasErr atomic . Bool
// also save the directory itself (path) if it exists in the filer
// also save the directory itself (path) if it exists in the filer
if e , getErr := filer_pb . GetEntry ( context . Background ( ) , filerClient , util . FullPath ( path ) ) ; getErr != nil {
if e , getErr := filer_pb . GetEntry ( context . Background ( ) , filerClient , util . FullPath ( path ) ) ; getErr != nil {
@ -160,8 +171,16 @@ func doTraverseBfsAndSaving(filerClient filer_pb.FilerClient, writer io.Writer,
Dir : parentDir ,
Dir : parentDir ,
Entry : e ,
Entry : e ,
}
}
if hasErr . Load ( ) {
// fail-fast: do not continue emitting partial results after first error
return firstErr
}
if genErr := genFn ( protoMessage , outputChan ) ; genErr != nil {
if genErr := genFn ( protoMessage , outputChan ) ; genErr != nil {
fmt . Fprintf ( writer , "marshall error: %v\n" , genErr )
once . Do ( func ( ) {
firstErr = genErr
hasErr . Store ( true )
} )
return genErr
} else {
} else {
if e . IsDirectory {
if e . IsDirectory {
atomic . AddUint64 ( & dirCount , 1 )
atomic . AddUint64 ( & dirCount , 1 )
@ -171,10 +190,12 @@ func doTraverseBfsAndSaving(filerClient filer_pb.FilerClient, writer io.Writer,
}
}
}
}
err := filer_pb . TraverseBfs ( filerClient , util . FullPath ( path ) , func ( parentPath util . FullPath , entry * filer_pb . Entry ) {
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
err := filer_pb . TraverseBfsWithContext ( ctx , filerClient , util . FullPath ( path ) , func ( parentPath util . FullPath , entry * filer_pb . Entry ) error {
if strings . HasPrefix ( string ( parentPath ) , filer . SystemLogDir ) {
if strings . HasPrefix ( string ( parentPath ) , filer . SystemLogDir ) {
return
return nil
}
}
protoMessage := & filer_pb . FullEntry {
protoMessage := & filer_pb . FullEntry {
@ -182,9 +203,17 @@ func doTraverseBfsAndSaving(filerClient filer_pb.FilerClient, writer io.Writer,
Entry : entry ,
Entry : entry ,
}
}
if err := genFn ( protoMessage , outputChan ) ; err != nil {
fmt . Fprintf ( writer , "marshall error: %v\n" , err )
return
if hasErr . Load ( ) {
// fail-fast: stop traversal once an error is observed.
return firstErr
}
if genErr := genFn ( protoMessage , outputChan ) ; genErr != nil {
once . Do ( func ( ) {
firstErr = genErr
hasErr . Store ( true )
cancel ( )
} )
return genErr
}
}
if entry . IsDirectory {
if entry . IsDirectory {
@ -197,11 +226,20 @@ func doTraverseBfsAndSaving(filerClient filer_pb.FilerClient, writer io.Writer,
println ( parentPath . Child ( entry . Name ) )
println ( parentPath . Child ( entry . Name ) )
}
}
return nil
} )
} )
close ( outputChan )
close ( outputChan )
wg . Wait ( )
wg . Wait ( )
saveErr := <- saveErrChan
if firstErr != nil {
return firstErr
}
if saveErr != nil {
return saveErr
}
if err == nil && writer != nil {
if err == nil && writer != nil {
fmt . Fprintf ( writer , "total %d directories, %d files\n" , dirCount , fileCount )
fmt . Fprintf ( writer , "total %d directories, %d files\n" , dirCount , fileCount )