@@ -768,14 +768,145 @@ func (inode *Inode) sendUpload(priority int) bool {
768768 return false
769769}
770770
771- func (inode * Inode ) sendRename () {
772- cloud , key := inode .cloud ()
773- if inode .isDir () {
774- key += "/"
771+ func (inode * Inode ) finishErrorSendRenameSpecial (err error , from string , key string , oldParent * Inode , oldName string ) {
772+ mappedErr := mapAwsError (err )
773+ if mappedErr == syscall .ENOENT || mappedErr == syscall .ERANGE {
774+ s3Log .Warnf ("Conflict detected (inode %v): failed to copy %v to %v: %v. File is removed remotely, dropping cache" , inode .Id , from , key , err )
775+ inode .mu .Lock ()
776+ newParent := inode .Parent
777+ oldParent := inode .oldParent
778+ oldName := inode .oldName
779+ inode .oldParent = nil
780+ inode .oldName = ""
781+ inode .renamingTo = false
782+ inode .resetCache ()
783+ inode .mu .Unlock ()
784+ newParent .removeChild (inode )
785+ if oldParent != nil {
786+ oldParent .mu .Lock ()
787+ if _ , ok := oldParent .dir .DeletedChildren [oldName ]; ok {
788+ delete (oldParent .dir .DeletedChildren , oldName )
789+ oldParent .addModified (- 1 )
790+ }
791+ oldParent .mu .Unlock ()
792+ }
793+ } else {
794+ fuseLog .Warnf ("Failed to copy %v to %v (rename): %v" , from , key , err )
795+ inode .mu .Lock ()
796+ inode .recordFlushError (err )
797+ if inode .Parent == oldParent && inode .Name == oldName {
798+ // Someone renamed the inode back to the original name
799+ // ...while we failed to copy it :)
800+ inode .oldParent = nil
801+ inode .oldName = ""
802+ inode .renamingTo = false
803+ inode .Parent .addModified (- 1 )
804+ if (inode .CacheState == ST_MODIFIED || inode .CacheState == ST_CREATED ) &&
805+ ! inode .isStillDirty () {
806+ inode .SetCacheState (ST_CACHED )
807+ inode .SetAttrTime (time .Now ())
808+ }
809+ }
810+ inode .mu .Unlock ()
811+ }
812+ }
813+
814+ func (inode * Inode ) finishSuccessSendRenameSpecial (from string , key string , oldParent * Inode , oldName string , newParent * Inode , newName string ) {
815+ fuseLog .Debugf ("Renamed %v to %v (rename)" , from , key )
816+ inode .mu .Lock ()
817+
818+ // Now we know that the object is accessible by the new name
819+ if inode .Parent == newParent && inode .Name == newName {
820+ // Just clear the old path
821+ inode .oldParent = nil
822+ inode .oldName = ""
823+ } else if inode .Parent == oldParent && inode .Name == oldName {
824+ // Someone renamed the inode back to the original name(!)
825+ inode .oldParent = nil
826+ inode .oldName = ""
827+ // Delete the new key instead of the old one (?)
828+ } else {
829+ // Someone renamed the inode again(!)
830+ inode .oldParent = newParent
831+ inode .oldName = newName
775832 }
833+ if (inode .CacheState == ST_MODIFIED || inode .CacheState == ST_CREATED ) &&
834+ ! inode .isStillDirty () {
835+ inode .SetCacheState (ST_CACHED )
836+ inode .SetAttrTime (time .Now ())
837+ }
838+ inode .renamingTo = false
839+ inode .mu .Unlock ()
840+
841+ oldParent .mu .Lock ()
842+ delete (oldParent .dir .DeletedChildren , oldName )
843+ oldParent .mu .Unlock ()
844+ // And track ModifiedChildren because rename is special - it takes two parents
845+ oldParent .addModified (- 1 )
846+ }
847+
848+ func (inode * Inode ) finishRenameFlush () {
849+ inode .mu .Lock ()
850+ inode .IsFlushing -= inode .fs .flags .MaxParallelParts
851+ atomic .AddInt64 (& inode .fs .activeFlushers , - 1 )
852+ inode .fs .WakeupFlusher ()
853+ inode .mu .Unlock ()
854+ }
855+
856+ func (inode * Inode ) startRenameFlush () {
776857 inode .IsFlushing += inode .fs .flags .MaxParallelParts
777858 atomic .AddInt64 (& inode .fs .stats .flushes , 1 )
778859 atomic .AddInt64 (& inode .fs .activeFlushers , 1 )
860+ }
861+
862+ func (inode * Inode ) sendRenameSpecial () {
863+ if inode .isDir () && inode .fs .flags .NoDirObject {
864+ return
865+ }
866+
867+ cloud , key := inode .cloud ()
868+ _ , from := inode .oldParent .cloud ()
869+
870+ from = appendChildName (from , inode .oldName )
871+ inode .renamingTo = true
872+ oldParent := inode .oldParent
873+ oldName := inode .oldName
874+ newParent := inode .Parent
875+ newName := inode .Name
876+ if inode .isDir () {
877+ from += "/"
878+ key += "/"
879+ }
880+
881+ inode .startRenameFlush ()
882+
883+ go func () {
884+ inode .fs .addInflightChange (key )
885+ _ , err := cloud .RenameBlob (& RenameBlobInput {
886+ Source : from ,
887+ Destination : key ,
888+ })
889+ inode .fs .completeInflightChange (key )
890+ if err != nil {
891+ mappedErr := mapAwsError (err )
892+ if mappedErr != syscall .ENOENT || ! inode .isDir () {
893+ inode .finishErrorSendRenameSpecial (err , from , key , oldParent , oldName )
894+ } else {
895+ inode .finishSuccessSendRenameSpecial (from , key , oldParent , oldName , newParent , newName )
896+ }
897+ } else {
898+ inode .finishSuccessSendRenameSpecial (from , key , oldParent , oldName , newParent , newName )
899+ }
900+ inode .finishRenameFlush ()
901+ }()
902+ }
903+
904+ func (inode * Inode ) sendRenameCopy () {
905+ cloud , key := inode .cloud ()
906+ if inode .isDir () {
907+ key += "/"
908+ }
909+ inode .startRenameFlush ()
779910 _ , from := inode .oldParent .cloud ()
780911 from = appendChildName (from , inode .oldName )
781912 oldParent := inode .oldParent
@@ -914,14 +1045,20 @@ func (inode *Inode) sendRename() {
9141045 }
9151046 }
9161047 }
917- inode .mu .Lock ()
918- inode .IsFlushing -= inode .fs .flags .MaxParallelParts
919- atomic .AddInt64 (& inode .fs .activeFlushers , - 1 )
920- inode .fs .WakeupFlusher ()
921- inode .mu .Unlock ()
1048+ inode .finishRenameFlush ()
9221049 }()
9231050}
9241051
1052+ func (inode * Inode ) sendRename () {
1053+ flags := inode .fs .flags
1054+ cloud := * inode .fs .cloud .Load ()
1055+ if cloud .Capabilities ().IsTigris && flags .TigrisRename {
1056+ inode .sendRenameSpecial ()
1057+ return
1058+ }
1059+ inode .sendRenameCopy ()
1060+ }
1061+
9251062func (inode * Inode ) sendUpdateMeta () {
9261063 // Update metadata by COPYing into the same object
9271064 // It results in the optimized implementation in S3
0 commit comments