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

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

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