* Fix storage Iterate bug and Add storage doctor to delete garbage attachments * Close object when used
This commit is contained in:
		
							parent
							
								
									30708d9ffe
								
							
						
					
					
						commit
						07489d0405
					
				
					 4 changed files with 83 additions and 3 deletions
				
			
		|  | @ -124,7 +124,6 @@ func runRecreateTable(ctx *cli.Context) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func runDoctor(ctx *cli.Context) error { | func runDoctor(ctx *cli.Context) error { | ||||||
| 
 |  | ||||||
| 	// Silence the default loggers
 | 	// Silence the default loggers
 | ||||||
| 	log.DelNamedLogger("console") | 	log.DelNamedLogger("console") | ||||||
| 	log.DelNamedLogger(log.DEFAULT) | 	log.DelNamedLogger(log.DEFAULT) | ||||||
|  |  | ||||||
|  | @ -144,6 +144,11 @@ func GetAttachmentByUUID(uuid string) (*Attachment, error) { | ||||||
| 	return getAttachmentByUUID(x, uuid) | 	return getAttachmentByUUID(x, uuid) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ExistAttachmentsByUUID returns true if attachment is exist by given UUID
 | ||||||
|  | func ExistAttachmentsByUUID(uuid string) (bool, error) { | ||||||
|  | 	return x.Where("`uuid`=?", uuid).Exist(new(Attachment)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName.
 | // GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName.
 | ||||||
| func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) { | func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) { | ||||||
| 	return getAttachmentByReleaseIDFileName(x, releaseID, fileName) | 	return getAttachmentByReleaseIDFileName(x, releaseID, fileName) | ||||||
|  |  | ||||||
							
								
								
									
										76
									
								
								modules/doctor/storage.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								modules/doctor/storage.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | ||||||
|  | // Copyright 2021 The Gitea Authors. All rights reserved.
 | ||||||
|  | // Use of this source code is governed by a MIT-style
 | ||||||
|  | // license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package doctor | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/storage" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func checkAttachmentStorageFiles(logger log.Logger, autofix bool) error { | ||||||
|  | 	var total, garbageNum int | ||||||
|  | 	var deletePaths []string | ||||||
|  | 	if err := storage.Attachments.IterateObjects(func(p string, obj storage.Object) error { | ||||||
|  | 		defer obj.Close() | ||||||
|  | 
 | ||||||
|  | 		total++ | ||||||
|  | 		stat, err := obj.Stat() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		exist, err := models.ExistAttachmentsByUUID(stat.Name()) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if !exist { | ||||||
|  | 			garbageNum++ | ||||||
|  | 			if autofix { | ||||||
|  | 				deletePaths = append(deletePaths, p) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}); err != nil { | ||||||
|  | 		logger.Error("storage.Attachments.IterateObjects failed: %v", err) | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if garbageNum > 0 { | ||||||
|  | 		if autofix { | ||||||
|  | 			var deletedNum int | ||||||
|  | 			for _, p := range deletePaths { | ||||||
|  | 				if err := storage.Attachments.Delete(p); err != nil { | ||||||
|  | 					log.Error("Delete attachment %s failed: %v", p, err) | ||||||
|  | 				} else { | ||||||
|  | 					deletedNum++ | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			logger.Info("%d missed information attachment detected, %d deleted.", garbageNum, deletedNum) | ||||||
|  | 		} else { | ||||||
|  | 			logger.Warn("Checked %d attachment, %d missed information.", total, garbageNum) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func checkStorageFiles(logger log.Logger, autofix bool) error { | ||||||
|  | 	if err := storage.Init(); err != nil { | ||||||
|  | 		logger.Error("storage.Init failed: %v", err) | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return checkAttachmentStorageFiles(logger, autofix) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	Register(&Check{ | ||||||
|  | 		Title:                      "Check if there is garbage storage files", | ||||||
|  | 		Name:                       "storages", | ||||||
|  | 		IsDefault:                  false, | ||||||
|  | 		Run:                        checkStorageFiles, | ||||||
|  | 		AbortIfFailed:              false, | ||||||
|  | 		SkipDatabaseInitialization: false, | ||||||
|  | 		Priority:                   1, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | @ -151,7 +151,7 @@ type minioFileInfo struct { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m minioFileInfo) Name() string { | func (m minioFileInfo) Name() string { | ||||||
| 	return m.ObjectInfo.Key | 	return path.Base(m.ObjectInfo.Key) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m minioFileInfo) Size() int64 { | func (m minioFileInfo) Size() int64 { | ||||||
|  | @ -219,7 +219,7 @@ func (m *MinioStorage) IterateObjects(fn func(path string, obj Object) error) er | ||||||
| 		} | 		} | ||||||
| 		if err := func(object *minio.Object, fn func(path string, obj Object) error) error { | 		if err := func(object *minio.Object, fn func(path string, obj Object) error) error { | ||||||
| 			defer object.Close() | 			defer object.Close() | ||||||
| 			return fn(strings.TrimPrefix(m.basePath, mObjInfo.Key), &minioObject{object}) | 			return fn(strings.TrimPrefix(mObjInfo.Key, m.basePath), &minioObject{object}) | ||||||
| 		}(object, fn); err != nil { | 		}(object, fn); err != nil { | ||||||
| 			return convertMinioErr(err) | 			return convertMinioErr(err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue