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

871 lines
20 KiB

  1. // Copyright (c) 2015-2021 MinIO, Inc.
  2. //
  3. // This file is part of MinIO Object Storage stack
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Affero General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Affero General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. package cmd
  18. import (
  19. "context"
  20. "errors"
  21. "fmt"
  22. "io"
  23. "strings"
  24. "sync"
  25. jsoniter "github.com/json-iterator/go"
  26. "github.com/klauspost/compress/s2"
  27. "github.com/minio/minio/internal/bpool"
  28. xioutil "github.com/minio/minio/internal/ioutil"
  29. "github.com/tinylib/msgp/msgp"
  30. "github.com/valyala/bytebufferpool"
  31. )
  32. // metadata stream format:
  33. //
  34. // The stream is s2 compressed.
  35. // https://github.com/klauspost/compress/tree/master/s2#s2-compression
  36. // This ensures integrity and reduces the size typically by at least 50%.
  37. //
  38. // All stream elements are msgpack encoded.
  39. //
  40. // 1 Integer, metacacheStreamVersion of the writer.
  41. // This can be used for managing breaking changes.
  42. //
  43. // For each element:
  44. // 1. Bool. If false at end of stream.
  45. // 2. String. Name of object. Directories contains a trailing slash.
  46. // 3. Binary. Blob of metadata. Length 0 on directories.
  47. // ... Next element.
  48. //
  49. // Streams can be assumed to be sorted in ascending order.
  50. // If the stream ends before a false boolean it can be assumed it was truncated.
  51. const metacacheStreamVersion = 2
  52. // metacacheWriter provides a serializer of metacache objects.
  53. type metacacheWriter struct {
  54. streamErr error
  55. mw *msgp.Writer
  56. creator func() error
  57. closer func() error
  58. blockSize int
  59. streamWg sync.WaitGroup
  60. reuseBlocks bool
  61. }
  62. // newMetacacheWriter will create a serializer that will write objects in given order to the output.
  63. // Provide a block size that affects latency. If 0 a default of 128KiB will be used.
  64. // Block size can be up to 4MiB.
  65. func newMetacacheWriter(out io.Writer, blockSize int) *metacacheWriter {
  66. if blockSize < 8<<10 {
  67. blockSize = 128 << 10
  68. }
  69. w := metacacheWriter{
  70. mw: nil,
  71. blockSize: blockSize,
  72. }
  73. w.creator = func() error {
  74. s2w := s2.NewWriter(out, s2.WriterBlockSize(blockSize), s2.WriterConcurrency(2))
  75. w.mw = msgp.NewWriter(s2w)
  76. w.creator = nil
  77. if err := w.mw.WriteByte(metacacheStreamVersion); err != nil {
  78. return err
  79. }
  80. w.closer = func() (err error) {
  81. defer func() {
  82. cerr := s2w.Close()
  83. if err == nil && cerr != nil {
  84. err = cerr
  85. }
  86. }()
  87. if w.streamErr != nil {
  88. return w.streamErr
  89. }
  90. if err = w.mw.WriteBool(false); err != nil {
  91. return err
  92. }
  93. return w.mw.Flush()
  94. }
  95. return nil
  96. }
  97. return &w
  98. }
  99. // write one or more objects to the stream in order.
  100. // It is favorable to send as many objects as possible in a single write,
  101. // but no more than math.MaxUint32
  102. func (w *metacacheWriter) write(objs ...metaCacheEntry) error {
  103. if w == nil {
  104. return errors.New("metacacheWriter: nil writer")
  105. }
  106. if len(objs) == 0 {
  107. return nil
  108. }
  109. if w.creator != nil {
  110. err := w.creator()
  111. w.creator = nil
  112. if err != nil {
  113. return fmt.Errorf("metacacheWriter: unable to create writer: %w", err)
  114. }
  115. if w.mw == nil {
  116. return errors.New("metacacheWriter: writer not initialized")
  117. }
  118. }
  119. for _, o := range objs {
  120. if len(o.name) == 0 {
  121. return errors.New("metacacheWriter: no name provided")
  122. }
  123. // Indicate EOS
  124. err := w.mw.WriteBool(true)
  125. if err != nil {
  126. return err
  127. }
  128. err = w.mw.WriteString(o.name)
  129. if err != nil {
  130. return err
  131. }
  132. err = w.mw.WriteBytes(o.metadata)
  133. if err != nil {
  134. return err
  135. }
  136. if w.reuseBlocks || o.reusable {
  137. metaDataPoolPut(o.metadata)
  138. }
  139. }
  140. return nil
  141. }
  142. // stream entries to the output.
  143. // The returned channel should be closed when done.
  144. // Any error is reported when closing the metacacheWriter.
  145. func (w *metacacheWriter) stream() (chan<- metaCacheEntry, error) {
  146. if w.creator != nil {
  147. err := w.creator()
  148. w.creator = nil
  149. if err != nil {
  150. return nil, fmt.Errorf("metacacheWriter: unable to create writer: %w", err)
  151. }
  152. if w.mw == nil {
  153. return nil, errors.New("metacacheWriter: writer not initialized")
  154. }
  155. }
  156. objs := make(chan metaCacheEntry, 100)
  157. w.streamErr = nil
  158. w.streamWg.Add(1)
  159. go func() {
  160. defer w.streamWg.Done()
  161. for o := range objs {
  162. if len(o.name) == 0 || w.streamErr != nil {
  163. continue
  164. }
  165. // Indicate EOS
  166. err := w.mw.WriteBool(true)
  167. if err != nil {
  168. w.streamErr = err
  169. continue
  170. }
  171. err = w.mw.WriteString(o.name)
  172. if err != nil {
  173. w.streamErr = err
  174. continue
  175. }
  176. err = w.mw.WriteBytes(o.metadata)
  177. if w.reuseBlocks || o.reusable {
  178. metaDataPoolPut(o.metadata)
  179. }
  180. if err != nil {
  181. w.streamErr = err
  182. continue
  183. }
  184. }
  185. }()
  186. return objs, nil
  187. }
  188. // Close and release resources.
  189. func (w *metacacheWriter) Close() error {
  190. if w == nil || w.closer == nil {
  191. return nil
  192. }
  193. w.streamWg.Wait()
  194. err := w.closer()
  195. w.closer = nil
  196. return err
  197. }
  198. // Reset and start writing to new writer.
  199. // Close must have been called before this.
  200. func (w *metacacheWriter) Reset(out io.Writer) {
  201. w.streamErr = nil
  202. w.creator = func() error {
  203. s2w := s2.NewWriter(out, s2.WriterBlockSize(w.blockSize), s2.WriterConcurrency(2))
  204. w.mw = msgp.NewWriter(s2w)
  205. w.creator = nil
  206. if err := w.mw.WriteByte(metacacheStreamVersion); err != nil {
  207. return err
  208. }
  209. w.closer = func() error {
  210. if w.streamErr != nil {
  211. return w.streamErr
  212. }
  213. if err := w.mw.WriteBool(false); err != nil {
  214. return err
  215. }
  216. if err := w.mw.Flush(); err != nil {
  217. return err
  218. }
  219. return s2w.Close()
  220. }
  221. return nil
  222. }
  223. }
  224. var s2DecPool = bpool.Pool[*s2.Reader]{New: func() *s2.Reader {
  225. // Default alloc block for network transfer.
  226. return s2.NewReader(nil, s2.ReaderAllocBlock(16<<10))
  227. }}
  228. // metacacheReader allows reading a cache stream.
  229. type metacacheReader struct {
  230. mr *msgp.Reader
  231. current metaCacheEntry
  232. err error // stateful error
  233. closer func()
  234. creator func() error
  235. }
  236. // newMetacacheReader creates a new cache reader.
  237. // Nothing will be read from the stream yet.
  238. func newMetacacheReader(r io.Reader) *metacacheReader {
  239. dec := s2DecPool.Get()
  240. dec.Reset(r)
  241. mr := msgpNewReader(dec)
  242. return &metacacheReader{
  243. mr: mr,
  244. closer: func() {
  245. dec.Reset(nil)
  246. s2DecPool.Put(dec)
  247. readMsgpReaderPoolPut(mr)
  248. },
  249. creator: func() error {
  250. v, err := mr.ReadByte()
  251. if err != nil {
  252. return err
  253. }
  254. switch v {
  255. case 1, 2:
  256. default:
  257. return fmt.Errorf("metacacheReader: Unknown version: %d", v)
  258. }
  259. return nil
  260. },
  261. }
  262. }
  263. func (r *metacacheReader) checkInit() {
  264. if r.creator == nil || r.err != nil {
  265. return
  266. }
  267. r.err = r.creator()
  268. r.creator = nil
  269. }
  270. // peek will return the name of the next object.
  271. // Will return io.EOF if there are no more objects.
  272. // Should be used sparingly.
  273. func (r *metacacheReader) peek() (metaCacheEntry, error) {
  274. r.checkInit()
  275. if r.err != nil {
  276. return metaCacheEntry{}, r.err
  277. }
  278. if r.current.name != "" {
  279. return r.current, nil
  280. }
  281. if more, err := r.mr.ReadBool(); !more {
  282. switch err {
  283. case nil:
  284. r.err = io.EOF
  285. return metaCacheEntry{}, io.EOF
  286. case io.EOF:
  287. r.err = io.ErrUnexpectedEOF
  288. return metaCacheEntry{}, io.ErrUnexpectedEOF
  289. }
  290. r.err = err
  291. return metaCacheEntry{}, err
  292. }
  293. var err error
  294. if r.current.name, err = r.mr.ReadString(); err != nil {
  295. if err == io.EOF {
  296. err = io.ErrUnexpectedEOF
  297. }
  298. r.err = err
  299. return metaCacheEntry{}, err
  300. }
  301. r.current.metadata, err = r.mr.ReadBytes(r.current.metadata[:0])
  302. if err == io.EOF {
  303. err = io.ErrUnexpectedEOF
  304. }
  305. r.err = err
  306. return r.current, err
  307. }
  308. // next will read one entry from the stream.
  309. // Generally not recommended for fast operation.
  310. func (r *metacacheReader) next() (metaCacheEntry, error) {
  311. r.checkInit()
  312. if r.err != nil {
  313. return metaCacheEntry{}, r.err
  314. }
  315. var m metaCacheEntry
  316. var err error
  317. if r.current.name != "" {
  318. m.name = r.current.name
  319. m.metadata = r.current.metadata
  320. r.current.name = ""
  321. r.current.metadata = nil
  322. return m, nil
  323. }
  324. if more, err := r.mr.ReadBool(); !more {
  325. switch err {
  326. case nil:
  327. r.err = io.EOF
  328. return m, io.EOF
  329. case io.EOF:
  330. r.err = io.ErrUnexpectedEOF
  331. return m, io.ErrUnexpectedEOF
  332. }
  333. r.err = err
  334. return m, err
  335. }
  336. if m.name, err = r.mr.ReadString(); err != nil {
  337. if err == io.EOF {
  338. err = io.ErrUnexpectedEOF
  339. }
  340. r.err = err
  341. return m, err
  342. }
  343. m.metadata, err = r.mr.ReadBytes(metaDataPoolGet())
  344. if err == io.EOF {
  345. err = io.ErrUnexpectedEOF
  346. }
  347. if len(m.metadata) == 0 && cap(m.metadata) >= metaDataReadDefault {
  348. metaDataPoolPut(m.metadata)
  349. m.metadata = nil
  350. }
  351. r.err = err
  352. return m, err
  353. }
  354. // next will read one entry from the stream.
  355. // Generally not recommended for fast operation.
  356. func (r *metacacheReader) nextEOF() bool {
  357. r.checkInit()
  358. if r.err != nil {
  359. return r.err == io.EOF
  360. }
  361. if r.current.name != "" {
  362. return false
  363. }
  364. _, err := r.peek()
  365. if err != nil {
  366. r.err = err
  367. return r.err == io.EOF
  368. }
  369. return false
  370. }
  371. // forwardTo will forward to the first entry that is >= s.
  372. // Will return io.EOF if end of stream is reached without finding any.
  373. func (r *metacacheReader) forwardTo(s string) error {
  374. r.checkInit()
  375. if r.err != nil {
  376. return r.err
  377. }
  378. if s == "" {
  379. return nil
  380. }
  381. if r.current.name != "" {
  382. if r.current.name >= s {
  383. return nil
  384. }
  385. r.current.name = ""
  386. r.current.metadata = nil
  387. }
  388. // temporary name buffer.
  389. tmp := make([]byte, 0, 256)
  390. for {
  391. if more, err := r.mr.ReadBool(); !more {
  392. switch err {
  393. case nil:
  394. r.err = io.EOF
  395. return io.EOF
  396. case io.EOF:
  397. r.err = io.ErrUnexpectedEOF
  398. return io.ErrUnexpectedEOF
  399. }
  400. r.err = err
  401. return err
  402. }
  403. // Read name without allocating more than 1 buffer.
  404. sz, err := r.mr.ReadStringHeader()
  405. if err != nil {
  406. r.err = err
  407. return err
  408. }
  409. if cap(tmp) < int(sz) {
  410. tmp = make([]byte, 0, sz+256)
  411. }
  412. tmp = tmp[:sz]
  413. _, err = r.mr.R.ReadFull(tmp)
  414. if err != nil {
  415. r.err = err
  416. return err
  417. }
  418. if string(tmp) >= s {
  419. r.current.name = string(tmp)
  420. r.current.metadata, r.err = r.mr.ReadBytes(nil)
  421. return r.err
  422. }
  423. // Skip metadata
  424. err = r.mr.Skip()
  425. if err != nil {
  426. if err == io.EOF {
  427. err = io.ErrUnexpectedEOF
  428. }
  429. r.err = err
  430. return err
  431. }
  432. }
  433. }
  434. // readN will return all the requested number of entries in order
  435. // or all if n < 0.
  436. // Will return io.EOF if end of stream is reached.
  437. // If requesting 0 objects nil error will always be returned regardless of at end of stream.
  438. // Use peek to determine if at end of stream.
  439. func (r *metacacheReader) readN(n int, inclDeleted, inclDirs, inclVersions bool, prefix string) (metaCacheEntriesSorted, error) {
  440. r.checkInit()
  441. if n == 0 {
  442. return metaCacheEntriesSorted{}, nil
  443. }
  444. if r.err != nil {
  445. return metaCacheEntriesSorted{}, r.err
  446. }
  447. var res metaCacheEntries
  448. if n > 0 {
  449. res = make(metaCacheEntries, 0, n)
  450. }
  451. if prefix != "" {
  452. if err := r.forwardTo(prefix); err != nil {
  453. return metaCacheEntriesSorted{}, err
  454. }
  455. }
  456. next, err := r.peek()
  457. if err != nil {
  458. return metaCacheEntriesSorted{}, err
  459. }
  460. if !next.hasPrefix(prefix) {
  461. return metaCacheEntriesSorted{}, io.EOF
  462. }
  463. if r.current.name != "" {
  464. if (inclDeleted || !r.current.isLatestDeletemarker()) && r.current.hasPrefix(prefix) && (inclDirs || r.current.isObject()) {
  465. res = append(res, r.current)
  466. }
  467. r.current.name = ""
  468. r.current.metadata = nil
  469. }
  470. for n < 0 || len(res) < n {
  471. if more, err := r.mr.ReadBool(); !more {
  472. switch err {
  473. case nil:
  474. r.err = io.EOF
  475. return metaCacheEntriesSorted{o: res}, io.EOF
  476. case io.EOF:
  477. r.err = io.ErrUnexpectedEOF
  478. return metaCacheEntriesSorted{o: res}, io.ErrUnexpectedEOF
  479. }
  480. r.err = err
  481. return metaCacheEntriesSorted{o: res}, err
  482. }
  483. var err error
  484. var meta metaCacheEntry
  485. if meta.name, err = r.mr.ReadString(); err != nil {
  486. if err == io.EOF {
  487. err = io.ErrUnexpectedEOF
  488. }
  489. r.err = err
  490. return metaCacheEntriesSorted{o: res}, err
  491. }
  492. if !meta.hasPrefix(prefix) {
  493. r.mr.R.Skip(1)
  494. return metaCacheEntriesSorted{o: res}, io.EOF
  495. }
  496. if meta.metadata, err = r.mr.ReadBytes(metaDataPoolGet()); err != nil {
  497. if err == io.EOF {
  498. err = io.ErrUnexpectedEOF
  499. }
  500. r.err = err
  501. return metaCacheEntriesSorted{o: res}, err
  502. }
  503. if len(meta.metadata) == 0 {
  504. metaDataPoolPut(meta.metadata)
  505. meta.metadata = nil
  506. }
  507. if !inclDirs && (meta.isDir() || (!inclVersions && meta.isObjectDir() && meta.isLatestDeletemarker())) {
  508. continue
  509. }
  510. if !inclDeleted && meta.isLatestDeletemarker() && meta.isObject() && !meta.isObjectDir() {
  511. continue
  512. }
  513. res = append(res, meta)
  514. }
  515. return metaCacheEntriesSorted{o: res}, nil
  516. }
  517. // readAll will return all remaining objects on the dst channel and close it when done.
  518. // The context allows the operation to be canceled.
  519. func (r *metacacheReader) readAll(ctx context.Context, dst chan<- metaCacheEntry) error {
  520. r.checkInit()
  521. if r.err != nil {
  522. return r.err
  523. }
  524. defer xioutil.SafeClose(dst)
  525. if r.current.name != "" {
  526. select {
  527. case <-ctx.Done():
  528. r.err = ctx.Err()
  529. return ctx.Err()
  530. case dst <- r.current:
  531. }
  532. r.current.name = ""
  533. r.current.metadata = nil
  534. }
  535. for {
  536. if more, err := r.mr.ReadBool(); !more {
  537. if err == io.EOF {
  538. err = io.ErrUnexpectedEOF
  539. }
  540. r.err = err
  541. return err
  542. }
  543. var err error
  544. var meta metaCacheEntry
  545. if meta.name, err = r.mr.ReadString(); err != nil {
  546. if err == io.EOF {
  547. err = io.ErrUnexpectedEOF
  548. }
  549. r.err = err
  550. return err
  551. }
  552. if meta.metadata, err = r.mr.ReadBytes(metaDataPoolGet()); err != nil {
  553. if err == io.EOF {
  554. err = io.ErrUnexpectedEOF
  555. }
  556. r.err = err
  557. return err
  558. }
  559. if len(meta.metadata) == 0 {
  560. metaDataPoolPut(meta.metadata)
  561. meta.metadata = nil
  562. }
  563. select {
  564. case <-ctx.Done():
  565. r.err = ctx.Err()
  566. return ctx.Err()
  567. case dst <- meta:
  568. }
  569. }
  570. }
  571. // readFn will return all remaining objects
  572. // and provide a callback for each entry read in order
  573. // as long as true is returned on the callback.
  574. func (r *metacacheReader) readFn(fn func(entry metaCacheEntry) bool) error {
  575. r.checkInit()
  576. if r.err != nil {
  577. return r.err
  578. }
  579. if r.current.name != "" {
  580. fn(r.current)
  581. r.current.name = ""
  582. r.current.metadata = nil
  583. }
  584. for {
  585. if more, err := r.mr.ReadBool(); !more {
  586. switch err {
  587. case io.EOF:
  588. r.err = io.ErrUnexpectedEOF
  589. return io.ErrUnexpectedEOF
  590. case nil:
  591. r.err = io.EOF
  592. return io.EOF
  593. }
  594. return err
  595. }
  596. var err error
  597. var meta metaCacheEntry
  598. if meta.name, err = r.mr.ReadString(); err != nil {
  599. if err == io.EOF {
  600. err = io.ErrUnexpectedEOF
  601. }
  602. r.err = err
  603. return err
  604. }
  605. if meta.metadata, err = r.mr.ReadBytes(nil); err != nil {
  606. if err == io.EOF {
  607. err = io.ErrUnexpectedEOF
  608. }
  609. r.err = err
  610. return err
  611. }
  612. // Send it!
  613. if !fn(meta) {
  614. return nil
  615. }
  616. }
  617. }
  618. // readNames will return all the requested number of names in order
  619. // or all if n < 0.
  620. // Will return io.EOF if end of stream is reached.
  621. func (r *metacacheReader) readNames(n int) ([]string, error) {
  622. r.checkInit()
  623. if r.err != nil {
  624. return nil, r.err
  625. }
  626. if n == 0 {
  627. return nil, nil
  628. }
  629. var res []string
  630. if n > 0 {
  631. res = make([]string, 0, n)
  632. }
  633. if r.current.name != "" {
  634. res = append(res, r.current.name)
  635. r.current.name = ""
  636. r.current.metadata = nil
  637. }
  638. for n < 0 || len(res) < n {
  639. if more, err := r.mr.ReadBool(); !more {
  640. switch err {
  641. case nil:
  642. r.err = io.EOF
  643. return res, io.EOF
  644. case io.EOF:
  645. r.err = io.ErrUnexpectedEOF
  646. return res, io.ErrUnexpectedEOF
  647. }
  648. return res, err
  649. }
  650. var err error
  651. var name string
  652. if name, err = r.mr.ReadString(); err != nil {
  653. r.err = err
  654. return res, err
  655. }
  656. if err = r.mr.Skip(); err != nil {
  657. if err == io.EOF {
  658. err = io.ErrUnexpectedEOF
  659. }
  660. r.err = err
  661. return res, err
  662. }
  663. res = append(res, name)
  664. }
  665. return res, nil
  666. }
  667. // skip n entries on the input stream.
  668. // If there are less entries left io.EOF is returned.
  669. func (r *metacacheReader) skip(n int) error {
  670. r.checkInit()
  671. if r.err != nil {
  672. return r.err
  673. }
  674. if n <= 0 {
  675. return nil
  676. }
  677. if r.current.name != "" {
  678. n--
  679. r.current.name = ""
  680. r.current.metadata = nil
  681. }
  682. for n > 0 {
  683. if more, err := r.mr.ReadBool(); !more {
  684. switch err {
  685. case nil:
  686. r.err = io.EOF
  687. return io.EOF
  688. case io.EOF:
  689. r.err = io.ErrUnexpectedEOF
  690. return io.ErrUnexpectedEOF
  691. }
  692. return err
  693. }
  694. if err := r.mr.Skip(); err != nil {
  695. if err == io.EOF {
  696. err = io.ErrUnexpectedEOF
  697. }
  698. r.err = err
  699. return err
  700. }
  701. if err := r.mr.Skip(); err != nil {
  702. if err == io.EOF {
  703. err = io.ErrUnexpectedEOF
  704. }
  705. r.err = err
  706. return err
  707. }
  708. n--
  709. }
  710. return nil
  711. }
  712. // Close and release resources.
  713. func (r *metacacheReader) Close() error {
  714. if r == nil || r.closer == nil {
  715. return nil
  716. }
  717. r.closer()
  718. r.closer = nil
  719. r.creator = nil
  720. return nil
  721. }
  722. // metacacheBlockWriter collects blocks and provides a callback to store them.
  723. type metacacheBlockWriter struct {
  724. wg sync.WaitGroup
  725. streamErr error
  726. blockEntries int
  727. }
  728. // newMetacacheBlockWriter provides a streaming block writer.
  729. // Each block is the size of the capacity of the input channel.
  730. // The caller should close to indicate the stream has ended.
  731. func newMetacacheBlockWriter(in <-chan metaCacheEntry, nextBlock func(b *metacacheBlock) error) *metacacheBlockWriter {
  732. w := metacacheBlockWriter{blockEntries: cap(in)}
  733. w.wg.Add(1)
  734. go func() {
  735. defer w.wg.Done()
  736. var current metacacheBlock
  737. var n int
  738. buf := bytebufferpool.Get()
  739. defer func() {
  740. buf.Reset()
  741. bytebufferpool.Put(buf)
  742. }()
  743. block := newMetacacheWriter(buf, 1<<20)
  744. defer block.Close()
  745. finishBlock := func() {
  746. if err := block.Close(); err != nil {
  747. w.streamErr = err
  748. return
  749. }
  750. current.data = buf.Bytes()
  751. w.streamErr = nextBlock(&current)
  752. // Prepare for next
  753. current.n++
  754. buf.Reset()
  755. block.Reset(buf)
  756. current.First = ""
  757. }
  758. for o := range in {
  759. if len(o.name) == 0 || w.streamErr != nil {
  760. continue
  761. }
  762. if current.First == "" {
  763. current.First = o.name
  764. }
  765. if n >= w.blockEntries-1 {
  766. finishBlock()
  767. n = 0
  768. }
  769. n++
  770. w.streamErr = block.write(o)
  771. if w.streamErr != nil {
  772. continue
  773. }
  774. current.Last = o.name
  775. }
  776. if n > 0 || current.n == 0 {
  777. current.EOS = true
  778. finishBlock()
  779. }
  780. }()
  781. return &w
  782. }
  783. // Close the stream.
  784. // The incoming channel must be closed before calling this.
  785. // Returns the first error the occurred during the writing if any.
  786. func (w *metacacheBlockWriter) Close() error {
  787. w.wg.Wait()
  788. return w.streamErr
  789. }
  790. type metacacheBlock struct {
  791. data []byte
  792. n int
  793. First string `json:"f"`
  794. Last string `json:"l"`
  795. EOS bool `json:"eos,omitempty"`
  796. }
  797. func (b metacacheBlock) headerKV() map[string]string {
  798. json := jsoniter.ConfigCompatibleWithStandardLibrary
  799. v, err := json.Marshal(b)
  800. if err != nil {
  801. bugLogIf(context.Background(), err) // Unlikely
  802. return nil
  803. }
  804. return map[string]string{fmt.Sprintf("%s-metacache-part-%d", ReservedMetadataPrefixLower, b.n): string(v)}
  805. }
  806. // pastPrefix returns true if the given prefix is before start of the block.
  807. func (b metacacheBlock) pastPrefix(prefix string) bool {
  808. if prefix == "" || strings.HasPrefix(b.First, prefix) {
  809. return false
  810. }
  811. // We have checked if prefix matches, so we can do direct compare.
  812. return b.First > prefix
  813. }
  814. // endedPrefix returns true if the given prefix ends within the block.
  815. func (b metacacheBlock) endedPrefix(prefix string) bool {
  816. if prefix == "" || strings.HasPrefix(b.Last, prefix) {
  817. return false
  818. }
  819. // We have checked if prefix matches, so we can do direct compare.
  820. return b.Last > prefix
  821. }