storage/StorageBaseStatementInternal.h
author Nicholas Nethercote <nnethercote@mozilla.com>
Fri, 16 Feb 2018 17:54:16 +1100
changeset 407868 32d6774930e55be5c03e8d631fc067a995623c1e
parent 373135 46153627ee5fa17c8cc67a76a9a468b36cfd1b52
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1438678 - Pass early prefs via shared memory instead of the command line. r=bobowen,jld,glandium. This patch replaces the large -intPrefs/-boolPrefs/-stringPrefs flags with a short-lived, anonymous, shared memory segment that is used to pass the early prefs. Removing the bloat from the command line is nice, but more important is the fact that this will let us pass more prefs at content process start-up, which will allow us to remove the early/late prefs split (bug 1436911). Although this mechanism is only used for prefs, it's conceivable that it could be used for other data that must be received very early by children, and for which the command line isn't ideal. Notable details: - Much of the patch deals with the various platform-specific ways of passing handles/fds to children. - Linux and Mac: we use a fixed fd (8) in combination with the new GeckoChildProcessHost::AddFdToRemap() function (which ensures the child won't close the fd). - Android: like Linux and Mac, but the handles get passed via "parcels" and we use the new SetPrefsFd() function instead of the fixed fd. - Windows: there is no need to duplicate the handle because Windows handles are system-wide. But we do use the new GeckoChildProcessHost::AddHandleToShare() function to add it to the list of inheritable handles. We also ensure that list is processed on all paths (MOZ_SANDBOX with sandbox, MOZ_SANDBOX without sandbox, non-MOZ_SANDBOX) so that the handles are marked as inheritable. The handle is passed via the -prefsHandle flag. The -prefsLen flag is used on all platforms to indicate the size of the shared memory segment. - The patch also moves the serialization/deserialization of the prefs in/out of the shared memory into libpref, which is a better spot for it. (This means Preferences::MustSendToContentProcesses() can be removed.) MozReview-Commit-ID: 8fREEBiYFvc

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: sw=2 ts=2 sts=2 expandtab
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_storage_StorageBaseStatementInternal_h_
#define mozilla_storage_StorageBaseStatementInternal_h_

#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "mozStorageHelper.h"

struct sqlite3;
struct sqlite3_stmt;
class mozIStorageBindingParamsArray;
class mozIStorageBindingParams;
class mozIStorageStatementCallback;
class mozIStoragePendingStatement;

namespace mozilla {
namespace storage {

#define STORAGEBASESTATEMENTINTERNAL_IID \
  {0xd18856c9, 0xbf07, 0x4ae2, {0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a}}

class Connection;
class StatementData;

class AsyncStatementFinalizer;

/**
 * Implementation-only interface and shared logix mix-in corresponding to
 * mozIStorageBaseStatement.  Both Statement and AsyncStatement inherit from
 * this. The interface aspect makes them look the same to implementation innards
 * that aren't publicly accessible.  The mix-in avoids code duplication in
 * common implementations of mozIStorageBaseStatement, albeit with some minor
 * performance/space overhead because we have to use defines to officially
 * implement the methods on Statement/AsyncStatement (and proxy to this base
 * class.)
 */
class StorageBaseStatementInternal : public nsISupports
{
public:
  NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID)

  /**
   * @return the connection that this statement belongs to.
   */
  Connection *getOwner()
  {
    return mDBConnection;
  }

  /**
   * Return the asynchronous statement, creating it if required.
   *
   * This is for use by the asynchronous execution code for StatementData
   * created by AsyncStatements.  Statement internally uses this method to
   * prepopulate StatementData with the sqlite3_stmt.
   *
   * @param[out] stmt
   *             The sqlite3_stmt for asynchronous use.
   * @return The SQLite result code for creating the statement if created,
   *         SQLITE_OK if creation was not required.
   */
  virtual int getAsyncStatement(sqlite3_stmt **_stmt) = 0;

  /**
   * Obtains the StatementData needed for asynchronous execution.
   *
   * This is for use by Connection to retrieve StatementData from statements
   * when executeAsync is invoked.
   *
   * @param[out] _data
   *             A reference to a StatementData object that will be populated
   *             upon successful execution of this method.
   * @return NS_OK if we were able to assemble the data, failure otherwise.
   */
  virtual nsresult getAsynchronousStatementData(StatementData &_data) = 0;

  /**
   * Construct a new BindingParams to be owned by the provided binding params
   * array.  This method exists so that BindingParamsArray does not need
   * factory logic to determine what type of BindingParams to instantiate.
   *
   * @param aOwner
   *        The binding params array to own the newly created binding params.
   * @return The new mozIStorageBindingParams instance appropriate to the
   *         underlying statement type.
   */
  virtual already_AddRefed<mozIStorageBindingParams> newBindingParams(
    mozIStorageBindingParamsArray *aOwner
  ) = 0;

protected: // mix-in bits are protected
  StorageBaseStatementInternal();

  RefPtr<Connection> mDBConnection;
  sqlite3 *mNativeConnection;

  /**
   * Our asynchronous statement.
   *
   * For Statement this is populated by the first invocation to
   * getAsyncStatement.
   *
   * For AsyncStatement, this is null at creation time and initialized by the
   * async thread when it calls getAsyncStatement the first time the statement
   * is executed.  (Or in the event of badly formed SQL, every time.)
   */
  sqlite3_stmt *mAsyncStatement;

  /**
   * Initiate asynchronous finalization by dispatching an event to the
   * asynchronous thread to finalize mAsyncStatement.  This acquires a reference
   * to this statement and proxies it back to the connection's owning thread
   * for release purposes.
   *
   * In the event the asynchronous thread is already gone or we otherwise fail
   * to dispatch an event to it we failover to invoking internalAsyncFinalize
   * directly.  (That's what the asynchronous finalizer would have called.)
   *
   * @note You must not call this method from your destructor because its
   *       operation assumes we are still alive.  Call internalAsyncFinalize
   *       directly in that case.
   */
  void asyncFinalize();

  /**
   * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by
   * attempting to dispatch to the asynchronous thread if available, finalizing
   * on this thread if it is not.
   *
   * @note Call this from your destructor, call asyncFinalize otherwise.
   */
  void destructorAsyncFinalize();

  NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray **_array);
  NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback *aCallback,
                          mozIStoragePendingStatement **_stmt);
  NS_IMETHOD EscapeStringForLIKE(const nsAString &aValue,
                                 char16_t aEscapeChar,
                                 nsAString &_escapedString);

  // Needs access to internalAsyncFinalize
  friend class AsyncStatementFinalizer;
};

NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal,
                              STORAGEBASESTATEMENTINTERNAL_IID)

#define NS_DECL_STORAGEBASESTATEMENTINTERNAL \
  virtual Connection *getOwner(); \
  virtual int getAsyncStatement(sqlite3_stmt **_stmt) override; \
  virtual nsresult getAsynchronousStatementData(StatementData &_data) override; \
  virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( \
    mozIStorageBindingParamsArray *aOwner) override;

/**
 * Helper macro to implement the proxying implementations.  Because we are
 * implementing methods that are part of mozIStorageBaseStatement and the
 * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't
 * need to provide declaration support.
 */
#define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs) \
  NS_IMETHODIMP _class::_method _declArgs                                 \
  {                                                                       \
    _optionalGuard                                                        \
    return StorageBaseStatementInternal::_method _invokeArgs;             \
  }


/**
 * Define proxying implementation for the given _class.  If a state invariant
 * needs to be checked and an early return possibly performed, pass the clause
 * to use as _optionalGuard.
 */
#define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \
  MIX_IMPL(_class, _optionalGuard,                                      \
           NewBindingParamsArray,                                       \
           (mozIStorageBindingParamsArray **_array),                    \
           (_array))                                                    \
  MIX_IMPL(_class, _optionalGuard,                                      \
           ExecuteAsync,                                                \
           (mozIStorageStatementCallback *aCallback,                    \
            mozIStoragePendingStatement **_stmt),                       \
           (aCallback, _stmt))                                          \
  MIX_IMPL(_class, _optionalGuard,                                      \
           EscapeStringForLIKE,                                         \
           (const nsAString &aValue, char16_t aEscapeChar,              \
            nsAString &_escapedString),                                 \
           (aValue, aEscapeChar, _escapedString))

/**
 * Name-building helper for BIND_GEN_IMPL.
 */
#define BIND_NAME_CONCAT(_nameBit, _concatBit) \
  Bind##_nameBit##_concatBit

/**
 * We have type-specific convenience methods for C++ implementations in
 * two different forms; by index and by name.  The following macro allows
 * us to avoid having to define repetitive things by hand.
 *
 * Because of limitations of macros and our desire to avoid requiring special
 * permutations for the null and blob cases (whose argument count varies),
 * we require that the argument declarations and corresponding invocation
 * usages are passed in.
 *
 * @param _class
 *        The class name.
 * @param _guard
 *        The guard clause to inject.
 * @param _declName
 *        The argument list (with parens) for the ByName variants.
 * @param _declIndex
 *        The argument list (with parens) for the ByIndex variants.
 * @param _invArgs
 *        The invocation argumment list.
 */
#define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \
  NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName             \
  {                                                                           \
    _guard                                                                    \
    mozIStorageBindingParams *params = getParams();                           \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
    return params->BIND_NAME_CONCAT(_name, ByName) _invArgs;                  \
  }                                                                           \
  NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex           \
  {                                                                           \
    _guard                                                                    \
    mozIStorageBindingParams *params = getParams();                           \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
    return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs;                 \
  }

/**
 * Implement BindByName/BindByIndex for the given class.
 *
 * @param _class The class name.
 * @param _optionalGuard The guard clause to inject.
 */
#define BIND_BASE_IMPLS(_class, _optionalGuard)             \
  NS_IMETHODIMP _class::BindByName(const nsACString &aName, \
                                   nsIVariant *aValue)      \
  {                                                         \
    _optionalGuard                                          \
    mozIStorageBindingParams *params = getParams();         \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);         \
    return params->BindByName(aName, aValue);               \
  }                                                         \
  NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex,        \
                                    nsIVariant *aValue)     \
  {                                                         \
    _optionalGuard                                          \
    mozIStorageBindingParams *params = getParams();         \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);         \
    return params->BindByIndex(aIndex, aValue);             \
  }

/**
 * Define the various Bind*ByIndex, Bind*ByName stubs that just end up proxying
 * to the params object.
 */
#define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard) \
  BIND_BASE_IMPLS(_class, _optionalGuard)                \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                UTF8String,                              \
                (const nsACString &aWhere,               \
                 const nsACString &aValue),              \
                (uint32_t aWhere,                        \
                 const nsACString &aValue),              \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                String,                                  \
                (const nsACString &aWhere,               \
                 const nsAString  &aValue),              \
                (uint32_t aWhere,                        \
                 const nsAString  &aValue),              \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                Double,                                  \
                (const nsACString &aWhere,               \
                 double aValue),                         \
                (uint32_t aWhere,                        \
                 double aValue),                         \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                Int32,                                   \
                (const nsACString &aWhere,               \
                 int32_t aValue),                        \
                (uint32_t aWhere,                        \
                 int32_t aValue),                        \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                Int64,                                   \
                (const nsACString &aWhere,               \
                 int64_t aValue),                        \
                (uint32_t aWhere,                        \
                 int64_t aValue),                        \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                Null,                                    \
                (const nsACString &aWhere),              \
                (uint32_t aWhere),                       \
                (aWhere))                                \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                Blob,                                    \
                (const nsACString &aWhere,               \
                 const uint8_t *aValue,                  \
                 uint32_t aValueSize),                   \
                (uint32_t aWhere,                        \
                 const uint8_t *aValue,                  \
                 uint32_t aValueSize),                   \
                (aWhere, aValue, aValueSize))            \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                StringAsBlob,                            \
                (const nsACString &aWhere,               \
                 const nsAString& aValue),               \
                (uint32_t aWhere,                        \
                 const nsAString& aValue),               \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                UTF8StringAsBlob,                        \
                (const nsACString &aWhere,               \
                 const nsACString& aValue),              \
                (uint32_t aWhere,                        \
                 const nsACString& aValue),              \
                (aWhere, aValue))                        \
  BIND_GEN_IMPL(_class, _optionalGuard,                  \
                AdoptedBlob,                             \
                (const nsACString &aWhere,               \
                 uint8_t *aValue,                        \
                 uint32_t aValueSize),                   \
                (uint32_t aWhere,                        \
                 uint8_t *aValue,                        \
                 uint32_t aValueSize),                   \
                (aWhere, aValue, aValueSize))



} // namespace storage
} // namespace mozilla

#endif // mozilla_storage_StorageBaseStatementInternal_h_