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 19 kB

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

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