summaryrefslogtreecommitdiff
path: root/dom/cache/Context.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/cache/Context.h')
-rw-r--r--dom/cache/Context.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/dom/cache/Context.h b/dom/cache/Context.h
new file mode 100644
index 0000000000..278302bf6d
--- /dev/null
+++ b/dom/cache/Context.h
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_dom_cache_Context_h
+#define mozilla_dom_cache_Context_h
+
+#include "mozilla/dom/cache/Types.h"
+#include "nsCOMPtr.h"
+#include "nsISupportsImpl.h"
+#include "nsProxyRelease.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsTObserverArray.h"
+
+class nsIEventTarget;
+class nsIThread;
+
+namespace mozilla {
+namespace dom {
+
+namespace quota {
+
+class DirectoryLock;
+
+} // namespace quota
+
+namespace cache {
+
+class Action;
+class Manager;
+
+// The Context class is RAII-style class for managing IO operations within the
+// Cache.
+//
+// When a Context is created it performs the complicated steps necessary to
+// initialize the QuotaManager. Action objects dispatched on the Context are
+// delayed until this initialization is complete. They are then allow to
+// execute on any specified thread. Once all references to the Context are
+// gone, then the steps necessary to release the QuotaManager are performed.
+// After initialization the Context holds a self reference, so it will stay
+// alive until one of three conditions occur:
+//
+// 1) The Manager will call Context::AllowToClose() when all of the actors
+// have removed themselves as listener. This means an idle context with
+// no active DOM objects will close gracefully.
+// 2) The QuotaManager aborts all operations so it can delete the files.
+// In this case the QuotaManager calls Client::AbortOperations() which
+// in turn cancels all existing Action objects and then marks the Manager
+// as invalid.
+// 3) Browser shutdown occurs and the Manager calls Context::CancelAll().
+//
+// In either case, though, the Action objects must be destroyed first to
+// allow the Context to be destroyed.
+//
+// While the Context performs operations asynchronously on threads, all of
+// methods in its public interface must be called on the same thread
+// originally used to create the Context.
+//
+// As an invariant, all Context objects must be destroyed before permitting
+// the "profile-before-change" shutdown event to complete. This is ensured
+// via the code in ShutdownObserver.cpp.
+class Context final
+{
+ typedef mozilla::dom::quota::DirectoryLock DirectoryLock;
+
+public:
+ // Define a class allowing other threads to hold the Context alive. This also
+ // allows these other threads to safely close or cancel the Context.
+ class ThreadsafeHandle final
+ {
+ friend class Context;
+ public:
+ void AllowToClose();
+ void InvalidateAndAllowToClose();
+ private:
+ explicit ThreadsafeHandle(Context* aContext);
+ ~ThreadsafeHandle();
+
+ // disallow copying
+ ThreadsafeHandle(const ThreadsafeHandle&) = delete;
+ ThreadsafeHandle& operator=(const ThreadsafeHandle&) = delete;
+
+ void AllowToCloseOnOwningThread();
+ void InvalidateAndAllowToCloseOnOwningThread();
+
+ void ContextDestroyed(Context* aContext);
+
+ // Cleared to allow the Context to close. Only safe to access on
+ // owning thread.
+ RefPtr<Context> mStrongRef;
+
+ // Used to support cancelation even while the Context is already allowed
+ // to close. Cleared by ~Context() calling ContextDestroyed(). Only
+ // safe to access on owning thread.
+ Context* mWeakRef;
+
+ nsCOMPtr<nsIThread> mOwningThread;
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::Context::ThreadsafeHandle)
+ };
+
+ // Different objects hold references to the Context while some work is being
+ // performed asynchronously. These objects must implement the Activity
+ // interface and register themselves with the AddActivity(). When they are
+ // destroyed they must call RemoveActivity(). This allows the Context to
+ // cancel any outstanding Activity work when the Context is cancelled.
+ class Activity
+ {
+ public:
+ virtual void Cancel() = 0;
+ virtual bool MatchesCacheId(CacheId aCacheId) const = 0;
+ };
+
+ // Create a Context attached to the given Manager. The given Action
+ // will run on the QuotaManager IO thread. Note, this Action must
+ // be execute synchronously.
+ static already_AddRefed<Context>
+ Create(Manager* aManager, nsIThread* aTarget,
+ Action* aInitAction, Context* aOldContext);
+
+ // Execute given action on the target once the quota manager has been
+ // initialized.
+ //
+ // Only callable from the thread that created the Context.
+ void Dispatch(Action* aAction);
+
+ // Cancel any Actions running or waiting to run. This should allow the
+ // Context to be released and Listener::RemoveContext() will be called
+ // when complete.
+ //
+ // Only callable from the thread that created the Context.
+ void CancelAll();
+
+ // True if CancelAll() has been called.
+ bool IsCanceled() const;
+
+ // Like CancelAll(), but also marks the Manager as "invalid".
+ void Invalidate();
+
+ // Remove any self references and allow the Context to be released when
+ // there are no more Actions to process.
+ void AllowToClose();
+
+ // Cancel any Actions running or waiting to run that operate on the given
+ // cache ID.
+ //
+ // Only callable from the thread that created the Context.
+ void CancelForCacheId(CacheId aCacheId);
+
+ void AddActivity(Activity* aActivity);
+ void RemoveActivity(Activity* aActivity);
+
+ const QuotaInfo&
+ GetQuotaInfo() const
+ {
+ return mQuotaInfo;
+ }
+
+ // Tell the Context that some state information has been orphaned in the
+ // data store and won't be cleaned up. The Context will leave the marker
+ // in place to trigger cleanup the next times its opened.
+ void NoteOrphanedData();
+
+private:
+ class Data;
+ class QuotaInitRunnable;
+ class ActionRunnable;
+
+ enum State
+ {
+ STATE_CONTEXT_PREINIT,
+ STATE_CONTEXT_INIT,
+ STATE_CONTEXT_READY,
+ STATE_CONTEXT_CANCELED
+ };
+
+ struct PendingAction
+ {
+ nsCOMPtr<nsIEventTarget> mTarget;
+ RefPtr<Action> mAction;
+ };
+
+ Context(Manager* aManager, nsIThread* aTarget, Action* aInitAction);
+ ~Context();
+ void Init(Context* aOldContext);
+ void Start();
+ void DispatchAction(Action* aAction, bool aDoomData = false);
+ void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
+ already_AddRefed<DirectoryLock> aDirectoryLock);
+
+
+ already_AddRefed<ThreadsafeHandle>
+ CreateThreadsafeHandle();
+
+ void
+ SetNextContext(Context* aNextContext);
+
+ void
+ DoomTargetData();
+
+ RefPtr<Manager> mManager;
+ nsCOMPtr<nsIThread> mTarget;
+ RefPtr<Data> mData;
+ State mState;
+ bool mOrphanedData;
+ QuotaInfo mQuotaInfo;
+ RefPtr<QuotaInitRunnable> mInitRunnable;
+ RefPtr<Action> mInitAction;
+ nsTArray<PendingAction> mPendingActions;
+
+ // Weak refs since activites must remove themselves from this list before
+ // being destroyed by calling RemoveActivity().
+ typedef nsTObserverArray<Activity*> ActivityList;
+ ActivityList mActivityList;
+
+ // The ThreadsafeHandle may have a strong ref back to us. This creates
+ // a ref-cycle that keeps the Context alive. The ref-cycle is broken
+ // when ThreadsafeHandle::AllowToClose() is called.
+ RefPtr<ThreadsafeHandle> mThreadsafeHandle;
+
+ RefPtr<DirectoryLock> mDirectoryLock;
+ RefPtr<Context> mNextContext;
+
+public:
+ NS_INLINE_DECL_REFCOUNTING(cache::Context)
+};
+
+} // namespace cache
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_cache_Context_h