2016-07-03 06:50:58 +00:00
package storage
import (
"fmt"
"os"
2019-10-29 07:35:16 +00:00
"github.com/chrislusf/seaweedfs/weed/storage/backend"
2019-05-22 05:41:20 +00:00
"github.com/chrislusf/seaweedfs/weed/storage/idx"
2019-04-19 04:43:36 +00:00
"github.com/chrislusf/seaweedfs/weed/storage/needle"
2018-07-08 09:28:04 +00:00
. "github.com/chrislusf/seaweedfs/weed/storage/types"
2016-07-03 06:50:58 +00:00
"github.com/chrislusf/seaweedfs/weed/util"
)
2019-04-19 08:56:38 +00:00
func CheckVolumeDataIntegrity ( v * Volume , indexFile * os . File ) ( lastAppendAtNs uint64 , e error ) {
2016-07-03 06:50:58 +00:00
var indexSize int64
if indexSize , e = verifyIndexFileIntegrity ( indexFile ) ; e != nil {
2019-04-19 08:56:38 +00:00
return 0 , fmt . Errorf ( "verifyIndexFileIntegrity %s failed: %v" , indexFile . Name ( ) , e )
2016-07-03 06:50:58 +00:00
}
if indexSize == 0 {
2019-04-30 03:22:19 +00:00
return 0 , nil
2016-07-03 06:50:58 +00:00
}
var lastIdxEntry [ ] byte
2019-04-19 07:39:34 +00:00
if lastIdxEntry , e = readIndexEntryAtOffset ( indexFile , indexSize - NeedleMapEntrySize ) ; e != nil {
2019-04-19 08:56:38 +00:00
return 0 , fmt . Errorf ( "readLastIndexEntry %s failed: %v" , indexFile . Name ( ) , e )
2016-07-03 06:50:58 +00:00
}
2019-05-22 05:41:20 +00:00
key , offset , size := idx . IdxFileEntry ( lastIdxEntry )
2019-04-19 08:56:38 +00:00
if offset . IsZero ( ) {
2019-04-30 03:22:19 +00:00
return 0 , nil
2016-07-25 06:54:40 +00:00
}
2020-09-11 18:34:10 +00:00
if size < 0 {
2020-09-12 11:07:04 +00:00
// read the deletion entry
if lastAppendAtNs , e = verifyDeletedNeedleIntegrity ( v . DataBackend , v . Version ( ) , key ) ; e != nil {
return lastAppendAtNs , fmt . Errorf ( "verifyNeedleIntegrity %s failed: %v" , indexFile . Name ( ) , e )
}
} else {
if lastAppendAtNs , e = verifyNeedleIntegrity ( v . DataBackend , v . Version ( ) , offset . ToAcutalOffset ( ) , key , size ) ; e != nil {
return lastAppendAtNs , fmt . Errorf ( "verifyNeedleIntegrity %s failed: %v" , indexFile . Name ( ) , e )
}
2019-04-19 08:56:38 +00:00
}
return
2016-07-03 06:50:58 +00:00
}
func verifyIndexFileIntegrity ( indexFile * os . File ) ( indexSize int64 , err error ) {
if indexSize , err = util . GetFileSize ( indexFile ) ; err == nil {
2019-04-19 07:39:34 +00:00
if indexSize % NeedleMapEntrySize != 0 {
2016-07-03 06:50:58 +00:00
err = fmt . Errorf ( "index file's size is %d bytes, maybe corrupted" , indexSize )
}
}
return
}
func readIndexEntryAtOffset ( indexFile * os . File , offset int64 ) ( bytes [ ] byte , err error ) {
if offset < 0 {
err = fmt . Errorf ( "offset %d for index file is invalid" , offset )
return
}
2019-04-19 07:39:34 +00:00
bytes = make ( [ ] byte , NeedleMapEntrySize )
2016-07-03 06:50:58 +00:00
_ , err = indexFile . ReadAt ( bytes , offset )
return
}
2020-08-19 00:04:28 +00:00
func verifyNeedleIntegrity ( datFile backend . BackendStorageFile , v needle . Version , offset int64 , key NeedleId , size Size ) ( lastAppendAtNs uint64 , err error ) {
2019-04-19 04:43:36 +00:00
n := new ( needle . Needle )
2020-10-28 04:03:06 +00:00
// case: node total memory 8g, set volumeLimitSize=2048 , save 10 files, every file size 2.2g or more , when we restart the volume server , while see out of memory error
// fix: When the size of the last file exceeds 10M, consider directly returning the last modify time
if size > 10 * 1024 * 1024 {
bytes , err := needle . ReadNeedleBlob ( datFile , offset + int64 ( size ) , 0 , v ) ;
if err == nil {
if v == needle . Version3 {
tsOffset := NeedleHeaderSize + 0 + needle . NeedleChecksumSize
n . AppendAtNs = util . BytesToUint64 ( bytes [ tsOffset : tsOffset + TimestampSize ] )
}
}
return n . AppendAtNs , err
}
2019-04-19 08:56:38 +00:00
if err = n . ReadData ( datFile , offset , size , v ) ; err != nil {
2020-03-17 16:43:57 +00:00
return n . AppendAtNs , fmt . Errorf ( "read data [%d,%d) : %v" , offset , offset + int64 ( size ) , err )
2016-07-03 06:50:58 +00:00
}
if n . Id != key {
2019-04-19 08:56:38 +00:00
return n . AppendAtNs , fmt . Errorf ( "index key %#x does not match needle's Id %#x" , key , n . Id )
2016-07-03 06:50:58 +00:00
}
2019-04-19 08:56:38 +00:00
return n . AppendAtNs , err
2016-07-03 06:50:58 +00:00
}
2020-09-12 11:07:04 +00:00
func verifyDeletedNeedleIntegrity ( datFile backend . BackendStorageFile , v needle . Version , key NeedleId ) ( lastAppendAtNs uint64 , err error ) {
n := new ( needle . Needle )
size := n . DiskSize ( v )
var fileSize int64
fileSize , _ , err = datFile . GetStat ( )
if err != nil {
return 0 , fmt . Errorf ( "GetStat: %v" , err )
}
if err = n . ReadData ( datFile , fileSize - size , Size ( 0 ) , v ) ; err != nil {
return n . AppendAtNs , fmt . Errorf ( "read data [%d,%d) : %v" , fileSize - size , size , err )
}
if n . Id != key {
return n . AppendAtNs , fmt . Errorf ( "index key %#x does not match needle's Id %#x" , key , n . Id )
}
return n . AppendAtNs , err
}