Uploaded image for project: 'Couchbase Server'
  1. Couchbase Server
  2. MB-49071

Investigate owning Cookie::engine_storage

    XMLWordPrintable

Details

    • Improvement
    • Resolution: Fixed
    • Major
    • Morpheus
    • None
    • couchbase-bucket
    • None
    • 1
    • KV Sept 2022

    Description

      TL;DR: Investigate using std::any for Cookie::engine_storage to allow the frontend to own the stored engine data, and destroy it if the operation fails.

      Also investigate other potential cleaner solutions.


      Currently, the engine-specific data stored in a Cookie while an operation is ewouldblocked is a void*.

      In some cases, this requires an object to be allocated in an initial engine call, and a raw pointer be stored in the cookie for use after some background work is complete.

      The engine then must ensure the frontend calls into the engine again after being notified, or the object may be leaked.

      This boils down to requiring that background tasks in this situation only ever call notifyIOComplete with success, and the "real" status of the operation must be managed separately.

      Alternatively, the background task may directly clear the engine storage and free the associated object - this makes the lifetime of the stored object slightly more convoluted, and is easily forgotten when adding new background tasks. This also comes with the typical drawbacks of "manual" delete e.g., thrown exceptions might unwind the stack and skip the clear+free, any and all early exits must account for the cleanup work.

      Successful flow

      Frontend                             Engine
       
                     getStats()
          --------------------------------->
                                           <Allocates something, schedules background task>
              engine_errc::would_block
          <--------------------------------
       
                         .
                         .
                         .
                                           <background work completes>
            notifyIOComplete(..., success)
          <--------------------------------
                         .
                         .
                         .
       
                     getStats()
          --------------------------------->
                                           <Retrieves background task result, frees thing>
                                           addStat(foo, bar)
              engine_errc::success
          <--------------------------------
      
      

      notifyIOComplete in a failure scenario

      Frontend                             Engine
       
                     getStats()
          --------------------------------->
                                           <Allocates something, schedules background task>
              engine_errc::would_block
          <--------------------------------
       
                         .
                         .
                         .
                                           <background work fails>
            notifyIOComplete(..., failed)
          <--------------------------------
                                           <allocated object leaked!>
      

      Workaround

      Frontend                             Engine
       
                     getStats()
          --------------------------------->
                                           <Allocates something, schedules background task>
              engine_errc::would_block
          <--------------------------------
       
                         .
                         .
                         .
                                           <background work fails!>
                                           <store real status somewhere>
            notifyIOComplete(..., success)
          <--------------------------------
                         .
                         .
                         .
       
                     getStats()
          --------------------------------->
                                           <Retrieves background task result, frees thing>
                                           <return real status>
              engine_errc::failed
          <--------------------------------
      
      

      To avoid this issue, Cookie::engine_storage could be made owning. std::any would allow the engine to store and (type-safely) retrieve an arbitrary object, but would also mean the cookie can destroy the contained object if the operation fails.

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              vesko.karaganev Vesko Karaganev
              james.harrison James Harrison (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes

                  PagerDuty