You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

file.go 22 kB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. package cache
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "path/filepath"
  7. "sync"
  8. "time"
  9. "gitlink.org.cn/cloudream/common/pkgs/logger"
  10. "gitlink.org.cn/cloudream/common/utils/io2"
  11. "gitlink.org.cn/cloudream/common/utils/lo2"
  12. "gitlink.org.cn/cloudream/common/utils/math2"
  13. "gitlink.org.cn/cloudream/common/utils/serder"
  14. "gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/fuse"
  15. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  16. )
  17. type CacheLevel int
  18. const (
  19. // 未加载
  20. LevelNotLoaded CacheLevel = iota
  21. // 缓存数据都完整,但仅加载了一次元数据,只能读取,不能修改。
  22. LevelReadOnly
  23. // 缓存数据都完整存在,但仅加载了元数据,没有加载文件数据
  24. LevelMetaLoaded
  25. // 缓存数据都完整存在,且已加载到内存中
  26. LevelComplete
  27. )
  28. func (l CacheLevel) String() string {
  29. var levels = []string{"NotLoaded", "ReadOnly", "MetaLoaded", "Complete"}
  30. return levels[l]
  31. }
  32. type FileInfo struct {
  33. // 文件总大小。可能会超过对应的远端文件的大小。
  34. // 此大小可能与本地缓存文件大小也不同,需要定时将本地缓存文件大小修正到与这个值相同。
  35. Size int64
  36. // 文件数据的版本号。如果大于0,则代表有未提交的修改
  37. DataRevision int
  38. // 文件元数据的版本号
  39. MetaRevision int
  40. // 数据段列表,按照段开始位置从小到大排列
  41. Segments []*Range
  42. // 文件对应的对象ID,仅在文件是一个缓存文件时才有值
  43. // ObjectID cdssdk.ObjectID
  44. // 文件对应的对象大小,仅在文件是一个缓存文件时才有值。
  45. // 此值代表有多少数据应该从远端加载,所以可能会小于远端实际大小
  46. ObjectSize int64
  47. // 如果本文件完全是一个缓存文件,那么这个字段记录了其内容的哈希值,用于在下载缓存数据时,检查远端文件是否被修改过
  48. // Hash cdssdk.FileHash
  49. // 文件的最后修改时间
  50. ModTime time.Time
  51. // 文件的权限
  52. Perm os.FileMode
  53. }
  54. func (f *FileInfo) Clone() FileInfo {
  55. n := *f
  56. n.Segments = make([]*Range, len(f.Segments))
  57. for i, seg := range f.Segments {
  58. n.Segments[i] = &Range{
  59. Position: seg.Position,
  60. Length: seg.Length,
  61. }
  62. }
  63. return n
  64. }
  65. type Range struct {
  66. Position int64
  67. Length int64
  68. }
  69. func (r *Range) GetPosition() int64 {
  70. return r.Position
  71. }
  72. func (r *Range) SetPosition(pos int64) {
  73. r.Position = pos
  74. }
  75. func (r *Range) GetLength() int64 {
  76. return r.Length
  77. }
  78. func (r *Range) SetLength(length int64) {
  79. r.Length = length
  80. }
  81. func (r *Range) End() int64 {
  82. return r.Position + r.Length
  83. }
  84. // 所有读写过程共用同一个CacheFile对象。
  85. // 不应该将此结构体保存到对象中
  86. type CacheFile struct {
  87. cache *Cache
  88. pathComps []string
  89. info FileInfo
  90. remoteObj *jcstypes.Object
  91. rwLock *sync.RWMutex
  92. readers []*CacheFileHandle
  93. writers []*CacheFileHandle
  94. saveMetaChan chan any
  95. saveMetaLock *sync.Mutex
  96. stopSaveMeta *bool
  97. isDeleted bool
  98. level CacheLevel
  99. refCount int
  100. freeTime time.Time
  101. changeLevelTime time.Time
  102. metaFile *os.File
  103. dataFile *os.File
  104. writeLock *sync.RWMutex
  105. // 缓存文件的状态,用于管理缓存文件的生命周期。不受rwLock保护,而是由Cache管理
  106. state cacheState
  107. }
  108. type cacheState struct {
  109. uploading *uploadingObject
  110. }
  111. func createNewCacheFile(cache *Cache, pathComps []string) (*CacheFile, error) {
  112. metaPath := cache.GetCacheMetaPath(pathComps...)
  113. dataPath := cache.GetCacheDataPath(pathComps...)
  114. info := FileInfo{
  115. DataRevision: 1,
  116. ModTime: time.Now(),
  117. Perm: 0755,
  118. }
  119. infoData, err := serder.ObjectToJSON(info)
  120. if err != nil {
  121. return nil, err
  122. }
  123. err = os.MkdirAll(filepath.Dir(metaPath), 0755)
  124. if err != nil {
  125. return nil, err
  126. }
  127. metaFile, err := os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
  128. if err != nil {
  129. return nil, fmt.Errorf("create cache meta file: %w", err)
  130. }
  131. err = io2.WriteAll(metaFile, infoData)
  132. if err != nil {
  133. metaFile.Close()
  134. return nil, fmt.Errorf("save cache meta file: %w", err)
  135. }
  136. dataFile, err := os.OpenFile(dataPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
  137. if err != nil {
  138. metaFile.Close()
  139. return nil, fmt.Errorf("create cache data file: %w", err)
  140. }
  141. ch := &CacheFile{
  142. cache: cache,
  143. pathComps: pathComps,
  144. info: info,
  145. rwLock: &sync.RWMutex{},
  146. saveMetaChan: make(chan any, 1),
  147. saveMetaLock: &sync.Mutex{},
  148. stopSaveMeta: new(bool),
  149. level: LevelComplete,
  150. freeTime: time.Now(),
  151. changeLevelTime: time.Now(),
  152. metaFile: metaFile,
  153. dataFile: dataFile,
  154. writeLock: &sync.RWMutex{},
  155. state: cacheState{},
  156. }
  157. go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
  158. return ch, nil
  159. }
  160. func loadCacheFile(cache *Cache, pathComps []string) (*CacheFile, error) {
  161. metaPath := cache.GetCacheMetaPath(pathComps...)
  162. dataPath := cache.GetCacheDataPath(pathComps...)
  163. dataFile, err := os.OpenFile(dataPath, os.O_RDWR, 0644)
  164. if err != nil {
  165. // 不要包装这里的err
  166. return nil, err
  167. }
  168. info := &FileInfo{}
  169. metaFile, err := os.OpenFile(metaPath, os.O_RDWR, 0644)
  170. if err != nil {
  171. // 如果有数据文件,而没有元数据文件,则创建一个元数据文件
  172. if !os.IsNotExist(err) {
  173. dataFile.Close()
  174. return nil, err
  175. }
  176. stat, err := dataFile.Stat()
  177. if err != nil {
  178. dataFile.Close()
  179. return nil, err
  180. }
  181. err = os.MkdirAll(filepath.Dir(metaPath), 0755)
  182. if err != nil {
  183. dataFile.Close()
  184. return nil, err
  185. }
  186. metaFile, err = os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
  187. if err != nil {
  188. dataFile.Close()
  189. return nil, err
  190. }
  191. info.Size = stat.Size()
  192. info.ModTime = stat.ModTime()
  193. info.Perm = stat.Mode().Perm()
  194. info.Segments = []*Range{{Position: 0, Length: info.Size}}
  195. info.MetaRevision = 1 // 未同步的文件视为已修改
  196. info.DataRevision = 1
  197. } else {
  198. err = serder.JSONToObjectStream(metaFile, info)
  199. if err != nil {
  200. dataFile.Close()
  201. return nil, err
  202. }
  203. }
  204. ch := &CacheFile{
  205. cache: cache,
  206. pathComps: pathComps,
  207. info: *info,
  208. rwLock: &sync.RWMutex{},
  209. saveMetaChan: make(chan any, 1),
  210. saveMetaLock: &sync.Mutex{},
  211. stopSaveMeta: new(bool),
  212. level: LevelComplete,
  213. freeTime: time.Now(),
  214. changeLevelTime: time.Now(),
  215. metaFile: metaFile,
  216. dataFile: dataFile,
  217. writeLock: &sync.RWMutex{},
  218. state: cacheState{},
  219. }
  220. go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
  221. return ch, nil
  222. }
  223. func newCacheFileFromObject(cache *Cache, pathComps []string, obj *jcstypes.Object) (*CacheFile, error) {
  224. metaPath := cache.GetCacheMetaPath(pathComps...)
  225. dataPath := cache.GetCacheDataPath(pathComps...)
  226. info := FileInfo{
  227. Size: obj.Size,
  228. ObjectSize: obj.Size,
  229. ModTime: obj.UpdateTime,
  230. Perm: 0755,
  231. }
  232. infoData, err := serder.ObjectToJSON(info)
  233. if err != nil {
  234. return nil, err
  235. }
  236. err = os.MkdirAll(filepath.Dir(metaPath), 0755)
  237. if err != nil {
  238. return nil, err
  239. }
  240. metaFile, err := os.OpenFile(metaPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
  241. if err != nil {
  242. return nil, fmt.Errorf("create cache meta file: %w", err)
  243. }
  244. err = io2.WriteAll(metaFile, infoData)
  245. if err != nil {
  246. metaFile.Close()
  247. return nil, fmt.Errorf("save cache meta file: %w", err)
  248. }
  249. dataFile, err := os.OpenFile(dataPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
  250. if err != nil {
  251. metaFile.Close()
  252. return nil, fmt.Errorf("create cache file: %w", err)
  253. }
  254. ch := &CacheFile{
  255. cache: cache,
  256. pathComps: pathComps,
  257. info: info,
  258. remoteObj: obj,
  259. rwLock: &sync.RWMutex{},
  260. saveMetaChan: make(chan any, 1),
  261. saveMetaLock: &sync.Mutex{},
  262. stopSaveMeta: new(bool),
  263. level: LevelComplete,
  264. freeTime: time.Now(),
  265. changeLevelTime: time.Now(),
  266. metaFile: metaFile,
  267. dataFile: dataFile,
  268. writeLock: &sync.RWMutex{},
  269. state: cacheState{},
  270. }
  271. go ch.serving(ch.saveMetaChan, ch.stopSaveMeta)
  272. return ch, nil
  273. }
  274. func loadReadOnlyCacheFile(cache *Cache, pathComps []string) (*CacheFile, error) {
  275. metaPath := cache.GetCacheMetaPath(pathComps...)
  276. dataPath := cache.GetCacheDataPath(pathComps...)
  277. dataStat, err := os.Stat(dataPath)
  278. if err != nil {
  279. // 不要包装这里的err
  280. return nil, err
  281. }
  282. if dataStat.IsDir() {
  283. return nil, fmt.Errorf("target is a directory")
  284. }
  285. info := &FileInfo{}
  286. metaData, err := os.ReadFile(metaPath)
  287. if err != nil {
  288. if !os.IsNotExist(err) {
  289. return nil, err
  290. }
  291. err = os.MkdirAll(filepath.Dir(metaPath), 0755)
  292. if err != nil {
  293. return nil, err
  294. }
  295. info.Size = dataStat.Size()
  296. info.ModTime = dataStat.ModTime()
  297. info.Perm = dataStat.Mode().Perm()
  298. info.Segments = []*Range{{Position: 0, Length: info.Size}}
  299. info.MetaRevision = 1 // 未同步的文件视为已修改
  300. info.DataRevision = 1
  301. // 实际的元数据文件在LevelUp时才创建
  302. } else {
  303. err = serder.JSONToObject(metaData, info)
  304. if err != nil {
  305. return nil, err
  306. }
  307. }
  308. ch := &CacheFile{
  309. cache: cache,
  310. pathComps: pathComps,
  311. info: *info,
  312. rwLock: &sync.RWMutex{},
  313. saveMetaChan: nil,
  314. saveMetaLock: &sync.Mutex{},
  315. stopSaveMeta: nil,
  316. level: LevelReadOnly,
  317. freeTime: time.Now(),
  318. changeLevelTime: time.Now(),
  319. metaFile: nil,
  320. dataFile: nil,
  321. writeLock: &sync.RWMutex{},
  322. state: cacheState{},
  323. }
  324. return ch, nil
  325. }
  326. func loadCacheFileInfo(cache *Cache, pathComps []string, dataFileInfo os.FileInfo) (*CacheEntryInfo, error) {
  327. metaPath := cache.GetCacheMetaPath(pathComps...)
  328. metaData, err := os.ReadFile(metaPath)
  329. if err == nil {
  330. info := &FileInfo{}
  331. err = serder.JSONToObject(metaData, info)
  332. if err != nil {
  333. return nil, err
  334. }
  335. return &CacheEntryInfo{
  336. PathComps: pathComps,
  337. Size: info.Size,
  338. Perm: info.Perm,
  339. ModTime: info.ModTime,
  340. IsDir: false,
  341. }, nil
  342. }
  343. if !os.IsNotExist(err) {
  344. return nil, err
  345. }
  346. return &CacheEntryInfo{
  347. PathComps: pathComps,
  348. Size: dataFileInfo.Size(),
  349. Perm: dataFileInfo.Mode(),
  350. ModTime: dataFileInfo.ModTime(),
  351. IsDir: false,
  352. }, nil
  353. }
  354. // 增加一个引用计数。不应该被Cache之外的代码调用。
  355. func (f *CacheFile) IncRef() {
  356. f.rwLock.Lock()
  357. defer f.rwLock.Unlock()
  358. f.refCount++
  359. }
  360. // 减少一个引用计数
  361. func (f *CacheFile) Release() {
  362. f.rwLock.Lock()
  363. defer f.rwLock.Unlock()
  364. f.refCount--
  365. if f.refCount == 0 {
  366. f.freeTime = time.Now()
  367. }
  368. }
  369. func (f *CacheFile) LevelDown(level CacheLevel) bool {
  370. if level <= LevelReadOnly {
  371. // 如果降级到不需要保存元数据的级别,就要先暂停保存元数据的操作
  372. f.saveMetaLock.Lock()
  373. defer f.saveMetaLock.Unlock()
  374. }
  375. f.rwLock.Lock()
  376. defer f.rwLock.Unlock()
  377. if level >= f.level {
  378. return true
  379. }
  380. // 缓存正在被使用时,不能降级
  381. if f.refCount > 0 {
  382. return false
  383. }
  384. switch f.level {
  385. case LevelComplete:
  386. f.dataFile.Close()
  387. f.level = LevelMetaLoaded
  388. if level >= f.level {
  389. break
  390. }
  391. fallthrough
  392. case LevelMetaLoaded:
  393. if !f.isDeleted {
  394. // TODO 日志
  395. f.saveMeta(f.info)
  396. }
  397. f.saveMetaChan = nil
  398. // 由于已经获取了saveMetaLock,所以这里设置true之后调用metaFile.Close不会导致saveMeta线程的保存失败
  399. // 因为saveMeta线程会先检查stopSaveMete的值
  400. *f.stopSaveMeta = true
  401. f.stopSaveMeta = nil
  402. f.metaFile.Close()
  403. f.level = LevelReadOnly
  404. if level >= f.level {
  405. break
  406. }
  407. fallthrough
  408. case LevelReadOnly:
  409. f.level = LevelNotLoaded
  410. if level >= f.level {
  411. break
  412. }
  413. fallthrough
  414. case LevelNotLoaded:
  415. }
  416. f.changeLevelTime = time.Now()
  417. return true
  418. }
  419. func (f *CacheFile) LevelUp(level CacheLevel) bool {
  420. f.rwLock.Lock()
  421. defer f.rwLock.Unlock()
  422. if level <= f.level {
  423. return true
  424. }
  425. // 缓存正在使用时,可以升级
  426. switch f.level {
  427. case LevelNotLoaded:
  428. f.level = LevelReadOnly
  429. if level <= f.level {
  430. break
  431. }
  432. fallthrough
  433. case LevelReadOnly:
  434. metaPath := f.cache.GetCacheMetaPath(f.pathComps...)
  435. metaFile, err := os.OpenFile(metaPath, os.O_RDWR|os.O_CREATE, 0644)
  436. if err != nil {
  437. logger.Warnf("open meta file %v: %v", metaPath, err)
  438. return false
  439. }
  440. f.saveMetaChan = make(chan any, 1)
  441. f.stopSaveMeta = new(bool)
  442. f.metaFile = metaFile
  443. f.level = LevelMetaLoaded
  444. go f.serving(f.saveMetaChan, f.stopSaveMeta)
  445. if level <= f.level {
  446. break
  447. }
  448. fallthrough
  449. case LevelMetaLoaded:
  450. dataPath := f.cache.GetCacheDataPath(f.pathComps...)
  451. dataFile, err := os.OpenFile(dataPath, os.O_RDWR|os.O_CREATE, 0644)
  452. if err != nil {
  453. logger.Warnf("open data file %v: %v", dataPath, err)
  454. return false
  455. }
  456. f.dataFile = dataFile
  457. f.level = LevelComplete
  458. if level <= f.level {
  459. break
  460. }
  461. fallthrough
  462. case LevelComplete:
  463. }
  464. f.changeLevelTime = time.Now()
  465. return true
  466. }
  467. func (f *CacheFile) RevisionUploaded(dataRev int, metaRev int) {
  468. f.rwLock.Lock()
  469. defer f.rwLock.Unlock()
  470. if dataRev != 0 && f.info.DataRevision == dataRev {
  471. f.info.DataRevision = 0
  472. }
  473. if metaRev != 0 && f.info.MetaRevision == metaRev {
  474. f.info.MetaRevision = 0
  475. }
  476. f.letSave()
  477. }
  478. func (f *CacheFile) Info() CacheEntryInfo {
  479. f.rwLock.RLock()
  480. defer f.rwLock.RUnlock()
  481. return CacheEntryInfo{
  482. PathComps: f.pathComps,
  483. Size: f.info.Size,
  484. Perm: f.info.Perm,
  485. ModTime: f.info.ModTime,
  486. IsDir: false,
  487. MetaRevision: f.info.MetaRevision,
  488. DataRevision: f.info.DataRevision,
  489. RefCount: f.refCount,
  490. FreeTime: f.freeTime,
  491. Level: f.level,
  492. ChangeLevelTime: f.changeLevelTime,
  493. }
  494. }
  495. func (f *CacheFile) Delete() {
  496. f.writeLock.Lock()
  497. defer f.writeLock.Unlock()
  498. f.rwLock.Lock()
  499. defer f.rwLock.Unlock()
  500. metaPath := f.cache.GetCacheMetaPath(f.pathComps...)
  501. dataPath := f.cache.GetCacheDataPath(f.pathComps...)
  502. os.Remove(metaPath)
  503. os.Remove(dataPath)
  504. // 不可能将isDeleted从true改为false,所以这里不需要使用stopSaveChan来等待saveMeta线程退出
  505. f.isDeleted = true
  506. if f.saveMetaChan != nil {
  507. f.letSave()
  508. }
  509. }
  510. func (f *CacheFile) Move(newPathComps []string) {
  511. f.writeLock.Lock()
  512. defer f.writeLock.Unlock()
  513. f.rwLock.Lock()
  514. defer f.rwLock.Unlock()
  515. f.pathComps = newPathComps
  516. if f.saveMetaChan != nil {
  517. f.letSave()
  518. }
  519. }
  520. // 打开一个写入句柄,同时支持读取
  521. func (f *CacheFile) Open(flags uint32) *CacheFileHandle {
  522. logger.Tracef("CacheFile.Open: %v, %#x", f.pathComps, flags)
  523. f.rwLock.Lock()
  524. defer f.rwLock.Unlock()
  525. f.refCount++
  526. h := &CacheFileHandle{
  527. file: f,
  528. remoteLock: &sync.Mutex{},
  529. revision: f.info.DataRevision,
  530. }
  531. if flags&uint32(os.O_RDWR) == uint32(os.O_RDWR) {
  532. h.readable = true
  533. h.writeable = true
  534. } else if flags&uint32(os.O_WRONLY) == uint32(os.O_WRONLY) {
  535. h.writeable = true
  536. } else if flags&uint32(os.O_RDONLY) == uint32(os.O_RDONLY) {
  537. h.readable = true
  538. }
  539. if f.remoteObj != nil {
  540. h.remote = newRemoteLoader(f)
  541. }
  542. if h.writeable {
  543. f.writers = append(f.writers, h)
  544. } else {
  545. f.readers = append(f.readers, h)
  546. }
  547. return h
  548. }
  549. // 打开一个读取句柄,用于同步本地文件到远端
  550. func (f *CacheFile) OpenReadWhenScanning() *CacheFileHandle {
  551. f.rwLock.Lock()
  552. defer f.rwLock.Unlock()
  553. f.refCount++
  554. h := &CacheFileHandle{
  555. file: f,
  556. remoteLock: &sync.Mutex{},
  557. revision: f.info.DataRevision,
  558. readable: true,
  559. }
  560. if f.remoteObj != nil {
  561. h.remote = newRemoteLoader(f)
  562. }
  563. f.readers = append(f.readers, h)
  564. return h
  565. }
  566. func (f *CacheFile) SetModTime(modTime time.Time) error {
  567. logger.Tracef("CacheFile.SetModTime: %v, %v", f.pathComps, modTime)
  568. f.rwLock.Lock()
  569. f.info.ModTime = modTime
  570. f.info.MetaRevision++
  571. f.rwLock.Unlock()
  572. f.letSave()
  573. return nil
  574. }
  575. func (f *CacheFile) Truncate(size int64) error {
  576. logger.Tracef("CacheFile.Truncate: %v, %v", f.pathComps, size)
  577. // 修改文件大小前不允许写入
  578. f.writeLock.Lock()
  579. defer f.writeLock.Unlock()
  580. err := f.dataFile.Truncate(size)
  581. if err != nil {
  582. return err
  583. }
  584. f.rwLock.Lock()
  585. defer f.rwLock.Unlock()
  586. // 调整能从远端下载的大小
  587. f.info.ObjectSize = math2.Min(f.info.ObjectSize, size)
  588. // 调整本地缓存文件里的有效数据大小
  589. if size < f.info.Size {
  590. f.info.Segments = TruncateRange(f.info.Segments, size)
  591. } else if size > f.info.Size {
  592. f.info.Segments = AddRange(f.info.Segments, &Range{Position: f.info.Size, Length: size - f.info.Size})
  593. }
  594. if f.info.Size != size {
  595. f.info.DataRevision++
  596. }
  597. f.info.Size = size
  598. f.letSave()
  599. return nil
  600. }
  601. func (f *CacheFile) serving(saveMetaChan chan any, stopSaveMeta *bool) {
  602. ticker := time.NewTicker(time.Second * 30)
  603. defer ticker.Stop()
  604. for {
  605. select {
  606. case _, ok := <-saveMetaChan:
  607. if !ok {
  608. return
  609. }
  610. case <-ticker.C:
  611. }
  612. f.saveMetaLock.Lock()
  613. if *stopSaveMeta {
  614. f.saveMetaLock.Unlock()
  615. break
  616. }
  617. f.rwLock.RLock()
  618. info := f.info.Clone()
  619. // 如果文件已被删除,则不能再保存元数据,防止覆盖掉新创建的同名文件
  620. if f.isDeleted {
  621. f.rwLock.RUnlock()
  622. f.saveMetaLock.Unlock()
  623. break
  624. }
  625. f.rwLock.RUnlock()
  626. // TODO 错误日志
  627. f.saveMeta(info)
  628. f.metaFile.Sync()
  629. f.saveMetaLock.Unlock()
  630. }
  631. }
  632. func (f *CacheFile) saveMeta(info FileInfo) error {
  633. jsonData, err := serder.ObjectToJSON(info)
  634. if err != nil {
  635. return err
  636. }
  637. err = f.metaFile.Truncate(0)
  638. if err != nil {
  639. return err
  640. }
  641. _, err = f.metaFile.Seek(0, io.SeekStart)
  642. if err != nil {
  643. return err
  644. }
  645. err = io2.WriteAll(f.metaFile, jsonData)
  646. if err != nil {
  647. return err
  648. }
  649. return nil
  650. }
  651. func (f *CacheFile) letSave() {
  652. select {
  653. case f.saveMetaChan <- nil:
  654. default:
  655. }
  656. }
  657. type CacheFileHandle struct {
  658. file *CacheFile
  659. readable bool
  660. writeable bool
  661. remote *RemoteLoader
  662. remoteLock *sync.Mutex
  663. revision int // 打开文件时,文件的版本号
  664. }
  665. func (h *CacheFileHandle) ReadAt(buf []byte, off int64) (int, error) {
  666. log := logger.WithField("F", "CacheFileHandle.ReadAt").
  667. WithField("Path", h.file.pathComps)
  668. log.Tracef("buf: %v, off: %v", len(buf), off)
  669. if !h.readable {
  670. return 0, fuse.ErrPermission
  671. }
  672. // 读取数据必须读满整个buf,否则就会被认为是文件已经结束了
  673. totalReadLen := 0
  674. for totalReadLen < len(buf) {
  675. curBuf := buf[totalReadLen:]
  676. curOff := off + int64(totalReadLen)
  677. h.file.rwLock.RLock()
  678. if curOff >= h.file.info.Size {
  679. h.file.rwLock.RUnlock()
  680. break
  681. }
  682. /// 1. 先尝试从本地缓存文件里读取
  683. rngIdx := FirstContainsIndex(h.file.info.Segments, curOff)
  684. if rngIdx >= 0 && h.file.info.Segments[rngIdx].End() > curOff {
  685. readLen := math2.Min(int64(len(curBuf)), h.file.info.Segments[rngIdx].End()-curOff)
  686. realReadLen, err := h.file.dataFile.ReadAt(curBuf[:readLen], curOff)
  687. totalReadLen += realReadLen
  688. h.file.rwLock.RUnlock()
  689. if err != nil {
  690. log.Tracef("read from local cache: %v", err)
  691. return totalReadLen, err
  692. }
  693. continue
  694. }
  695. // 否则从远端下载,计算一下要加载的长度
  696. loadLen := math2.Min(int64(len(curBuf)), h.file.info.ObjectSize-curOff)
  697. if rngIdx+1 < len(h.file.info.Segments) {
  698. // 最多加载到下一个段的开头
  699. loadLen = math2.Min(loadLen, h.file.info.Segments[rngIdx+1].Position-curOff)
  700. }
  701. h.file.rwLock.RUnlock()
  702. /// 2. 开始从远端下载数据
  703. if h.remote == nil {
  704. log.Warnf("no remote file")
  705. return totalReadLen, fmt.Errorf("no remote file")
  706. }
  707. // 由于RemoteLoader的Load方法没有加锁,所以这里要加锁,防止并发Seek导致的问题
  708. // 可以考虑在RemoteLoader里加锁,这样可以实现跨Writer共用Loader
  709. h.remoteLock.Lock()
  710. realLoadLen, err := h.remote.Load(curBuf[:loadLen], curOff)
  711. totalReadLen += realLoadLen
  712. if err != nil {
  713. h.remoteLock.Unlock()
  714. return totalReadLen, err
  715. }
  716. h.remoteLock.Unlock()
  717. log.Tracef("load from remote: %v", realLoadLen)
  718. /// 3. 数据加载完毕,写入到本地文件
  719. // 在写入到本地之前,先停止其他的写入,防止冲突
  720. h.file.writeLock.Lock()
  721. // 停止其他写入后,就可以计算一下实际要写回的长度。
  722. h.file.rwLock.RLock()
  723. loadRng := &Range{Position: curOff, Length: int64(realLoadLen)}
  724. DifferentRange(loadRng, h.file.info.Segments)
  725. h.file.rwLock.RUnlock()
  726. if loadRng.Length == 0 {
  727. h.file.writeLock.Unlock()
  728. continue
  729. }
  730. // 写入到本地缓存文件
  731. writeStart := loadRng.Position - curOff
  732. _, err = h.file.dataFile.WriteAt(curBuf[writeStart:writeStart+loadRng.Length], curOff)
  733. if err != nil {
  734. h.file.writeLock.Unlock()
  735. log.Warnf("save to local file: %v", err)
  736. return totalReadLen, err
  737. }
  738. log.Tracef("save to local: %v", loadRng.Length)
  739. h.file.writeLock.Unlock()
  740. // 提交到段列表里
  741. h.file.rwLock.Lock()
  742. h.file.info.Segments = AddRange(h.file.info.Segments, loadRng)
  743. h.file.rwLock.Unlock()
  744. h.file.letSave()
  745. }
  746. return totalReadLen, nil
  747. }
  748. func (h *CacheFileHandle) WriteAt(buf []byte, off int64) (int, error) {
  749. log := logger.WithField("F", "CacheFileHandle.WriteAt").WithField("Path", h.file.pathComps)
  750. log.Tracef("buf: %v, off: %v", len(buf), off)
  751. if !h.writeable {
  752. return 0, fuse.ErrPermission
  753. }
  754. // 允许多线程并行写入,但在数据加载期间不能写入
  755. h.file.writeLock.RLock()
  756. defer h.file.writeLock.RUnlock()
  757. // 写入到本地缓存文件
  758. writeLen, err := h.file.dataFile.WriteAt(buf, off)
  759. if err != nil {
  760. log.Tracef("save to local file: %v", err)
  761. return writeLen, err
  762. }
  763. // 提交到段列表里
  764. h.file.rwLock.Lock()
  765. defer h.file.rwLock.Unlock()
  766. h.file.info.Segments = AddRange(h.file.info.Segments, &Range{Position: off, Length: int64(writeLen)})
  767. h.file.info.Size = math2.Max(h.file.info.Size, off+int64(writeLen))
  768. h.file.info.DataRevision++
  769. h.file.letSave()
  770. return writeLen, nil
  771. }
  772. func (f *CacheFileHandle) Sync() error {
  773. log := logger.WithField("Path", f.file.pathComps)
  774. err := f.file.dataFile.Sync()
  775. if err != nil {
  776. log.Tracef("sync local file: %v", err)
  777. return err
  778. }
  779. return nil
  780. }
  781. func (f *CacheFileHandle) Close() error {
  782. f.Sync()
  783. if f.remote != nil {
  784. f.remote.Close()
  785. }
  786. f.file.rwLock.Lock()
  787. defer f.file.rwLock.Unlock()
  788. f.file.refCount--
  789. if f.file.refCount == 0 {
  790. f.file.freeTime = time.Now()
  791. }
  792. if f.writeable {
  793. f.file.writers = lo2.Remove(f.file.writers, f)
  794. } else if f.readable {
  795. f.file.readers = lo2.Remove(f.file.readers, f)
  796. }
  797. return nil
  798. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。