summaryrefslogtreecommitdiffstats
path: root/components/sync_sessions/synced_session_tracker.h
blob: a1a058b9ea6f2f9cd7c1ac5b436b6c76a76d77d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_
#define COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_

#include <map>
#include <set>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
#include "components/sync_sessions/synced_session.h"
#include "components/sync_sessions/tab_node_pool.h"

namespace sync_sessions {
class SyncSessionsClient;
}

namespace browser_sync {

// Class to manage synced sessions. The tracker will own all SyncedSession
// and SyncedSessionTab objects it creates, and deletes them appropriately on
// destruction.
// Note: SyncedSession objects are created for all synced sessions, including
// the local session (whose tag we maintain separately).
class SyncedSessionTracker {
 public:
  explicit SyncedSessionTracker(
      sync_sessions::SyncSessionsClient* sessions_client);
  ~SyncedSessionTracker();

  // We track and distinguish the local session from foreign sessions.
  void SetLocalSessionTag(const std::string& local_session_tag);

  // Fill a preallocated vector with all foreign sessions we're tracking (skips
  // the local session object). SyncedSession ownership remains within the
  // SyncedSessionTracker.
  // Returns true if we had foreign sessions to fill it with, false otherwise.
  bool LookupAllForeignSessions(
      std::vector<const sync_driver::SyncedSession*>* sessions) const;

  // Attempts to look up the session windows associatd with the session given
  // by |session_tag|. Ownership Of SessionWindows stays within the
  // SyncedSessionTracker.
  // If lookup succeeds:
  // - Fills windows with the SessionWindow pointers, returns true.
  // Else
  // - Returns false.
  bool LookupSessionWindows(
      const std::string& session_tag,
      std::vector<const sessions::SessionWindow*>* windows) const;

  // Attempts to look up the tab associated with the given tag and tab id.
  // Ownership of the SessionTab remains within the SyncedSessionTracker.
  // If lookup succeeds:
  // - Sets tab to point to the SessionTab, and returns true.
  // Else
  // - Returns false, tab is set to NULL.
  bool LookupSessionTab(const std::string& session_tag,
                        SessionID::id_type tab_id,
                        const sessions::SessionTab** tab) const;

  // Allows retrieval of existing data for the local session. Unlike GetSession
  // this won't create-if-not-present.
  bool LookupLocalSession(const sync_driver::SyncedSession** output) const;

  // Returns a pointer to the SyncedSession object associated with
  // |session_tag|.  If none exists, creates one. Ownership of the
  // SyncedSession remains within the SyncedSessionTracker.
  sync_driver::SyncedSession* GetSession(const std::string& session_tag);

  // Deletes the session associated with |session_tag| if it exists.
  // Returns true if the session existed and was deleted, false otherwise.
  bool DeleteSession(const std::string& session_tag);

  // Resets the tracking information for the session specified by |session_tag|.
  // This involves clearing all the windows and tabs from the session, while
  // keeping pointers saved in the synced_window_map_ and synced_tab_map_.
  // Once reset, all calls to PutWindowInSession and PutTabInWindow will denote
  // that the requested windows and tabs are owned (by setting the boolean
  // in their SessionWindowWrapper/SessionTabWrapper to true) and add them back
  // to their session. The next call to CleanupSession(...) will delete those
  // windows and tabs not owned.
  void ResetSessionTracking(const std::string& session_tag);

  // Deletes those windows and tabs associated with |session_tag| that are no
  // longer owned.
  // See ResetSessionTracking(...).
  void CleanupSession(const std::string& session_tag);

  // Adds the window with id |window_id| to the session specified by
  // |session_tag|, and markes the window as being owned. If none existed for
  // that session, creates one. Similarly, if the session did not exist yet,
  // creates it. Ownership of the SessionWindow remains within the
  // SyncedSessionTracker.
  void PutWindowInSession(const std::string& session_tag,
                          SessionID::id_type window_id);

  // Adds the tab with id |tab_id| to the window |window_id|, and marks it as
  // being owned. If none existed for that session, creates one. Ownership of
  // the SessionTab remains within the SyncedSessionTracker.
  // Note: GetSession(..) must have already been called with |session_tag| to
  // ensure we having mapping information for this session.
  void PutTabInWindow(const std::string& session_tag,
                      SessionID::id_type window_id,
                      SessionID::id_type tab_id,
                      size_t tab_index);

  // Returns a pointer to the SessionTab object associated with |tab_id| for
  // the session specified with |session_tag|. If none exists, creates one.
  // Ownership of the SessionTab remains within the SyncedSessionTracker.
  // |tab_node_id| must be a valid node id for the node backing this tab.
  sessions::SessionTab* GetTab(const std::string& session_tag,
                               SessionID::id_type tab_id,
                               int tab_node_id);

  // Fills |tab_node_ids| with the tab node ids (see GetTab) for all the tabs*
  // associated with the session having tag |session_tag|.
  // Returns false if we don't have any record of the session.  If no tabs were
  // found as part of the session, the return value will be true but
  // |tab_node_ids| will be empty.
  //
  // * - note that this only returns the ids we're aware of; it's possible we
  // don't have the latest tab state from a foreign session and it's also
  // possible we just haven't updated the tab_node_id for a tab yet, so the
  // result list should not be treated as authoritative.
  bool LookupTabNodeIds(const std::string& session_tag,
                        std::set<int>* tab_node_ids);

  // Free the memory for all dynamically allocated objects and clear the
  // tracking structures.
  void Clear();

  bool Empty() const {
    return synced_tab_map_.empty() && synced_session_map_.empty();
  }

  // Includes both foreign sessions and the local session.
  size_t num_synced_sessions() const { return synced_session_map_.size(); }

  // Returns the number of tabs associated with the specified session tag.
  size_t num_synced_tabs(const std::string& session_tag) const {
    SyncedTabMap::const_iterator iter = synced_tab_map_.find(session_tag);
    if (iter != synced_tab_map_.end()) {
      return iter->second.size();
    } else {
      return 0;
    }
  }

 private:
  // This enum is only used as a named input param for wrapper constructors. The
  // name of this enum and the wrapper's |owned| member variable are a bit
  // misleading. Technically you could argue that the data objects are in charge
  // of deleting their children data objects during their destructors, but this
  // tracker will often circumvent this mechanism. This tracker ensures that the
  // lifetime of both data object and wrapper are as identical as possible.

  // Alternatively, this |owned| concept can be thought of as being orphaned or
  // not. Although all data objects are tied to a session (via tag), they don't
  // always have a parent. Suppose we have information about a tab but no
  // information about it's parent window. This tab would be 'not owned', aka
  // orphaned. CleanupSession(...) can then delete any orphanted data objects
  // and wrapper for a given session via session tag.
  enum OwnedState { IS_OWNED, NOT_OWNED };

  // Datatypes for accessing session data. Neither of the *Wrappers actually
  // have ownership of the Windows/Tabs, they just provide id-based access to
  // them. The ownership remains within its containing session (for windows and
  // mapped tabs, unmapped tabs are owned by the unmapped_tabs_ container).
  // Note, we pair pointers with bools so that we can track what is owned and
  // what can be deleted (see ResetSessionTracking(..) and CleanupSession(..)
  // above).
  // The wrappers also serve as a convenient place to augment state stored in
  // SessionTab for sync purposes, such as |tab_node_id|.
  // IsOwned is used as a wrapper constructor parameter for readability.
  struct SessionTabWrapper {
    SessionTabWrapper()
        : tab_ptr(NULL),
          owned(false),
          tab_node_id(TabNodePool::kInvalidTabNodeID) {}
    SessionTabWrapper(sessions::SessionTab* tab_ptr,
                      OwnedState owned,
                      int tab_node_id)
        : tab_ptr(tab_ptr),
          owned(owned == IS_OWNED),
          tab_node_id(tab_node_id) {}
    sessions::SessionTab* tab_ptr;

    // This is used as part of a mark-and-sweep approach to garbage
    // collection for closed tabs that are no longer "in use", or "owned".
    // ResetSessionTracking will clear |owned| bits, and if it is not claimed
    // by a window by the time CleanupSession is called it will be deleted.
    bool owned;

    // This lets us identify the sync node that is "backing" this tab in the
    // sync model, whether it is part of a local or foreign session. The
    // "tab node id" is described in session_specifics.proto.
    int tab_node_id;
  };
  typedef std::map<SessionID::id_type, SessionTabWrapper> IDToSessionTabMap;
  typedef std::map<std::string, IDToSessionTabMap> SyncedTabMap;

  struct SessionWindowWrapper {
    SessionWindowWrapper() : window_ptr(NULL), owned(false) {}
    SessionWindowWrapper(sessions::SessionWindow* window_ptr, OwnedState owned)
        : window_ptr(window_ptr), owned(owned == IS_OWNED) {}
    sessions::SessionWindow* window_ptr;
    bool owned;
  };
  typedef std::map<SessionID::id_type, SessionWindowWrapper>
      IDToSessionWindowMap;
  typedef std::map<std::string, IDToSessionWindowMap> SyncedWindowMap;

  typedef std::map<std::string, sync_driver::SyncedSession*> SyncedSessionMap;

  // Helper methods for deleting SessionWindows and SessionTabs without owners.
  bool DeleteOldSessionWindowIfNecessary(SessionWindowWrapper window_wrapper);
  bool DeleteOldSessionTabIfNecessary(SessionTabWrapper tab_wrapper);

  // Implementation for GetTab(...) above, permits invalid tab_node_id.
  sessions::SessionTab* GetTabImpl(const std::string& session_tag,
                                   SessionID::id_type tab_id,
                                   int tab_node_id);

  // The client of the sync sessions datatype.
  sync_sessions::SyncSessionsClient* const sessions_client_;

  // Per client mapping of tab id's to their SessionTab objects.
  // Key: session tag.
  // Value: Tab id to SessionTabWrapper map.
  SyncedTabMap synced_tab_map_;

  // Per client mapping of the window id's to their SessionWindow objects.
  // Key: session_tag
  // Value: Window id to SessionWindowWrapper map.
  SyncedWindowMap synced_window_map_;

  // Per client mapping synced session objects.
  // Key: session tag.
  // Value: SyncedSession object pointer.
  SyncedSessionMap synced_session_map_;

  // The set of tabs that we have seen, and created SessionTab objects for, but
  // have not yet mapped to SyncedSessions. These are temporarily orphaned
  // tabs, and won't be deleted if we delete synced_session_map_, but are still
  // owned by the SyncedSessionTracker itself (and deleted on Clear()).
  std::set<sessions::SessionTab*> unmapped_tabs_;

  // The tag for this machine's local session, so we can distinguish the foreign
  // sessions.
  std::string local_session_tag_;

  DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker);
};

}  // namespace browser_sync

#endif  // COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_