1<!DOCTYPE html> 2<!-- 3Copyright (c) 2013 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/model/event_container.html"> 9<link rel="import" href="/tracing/model/object_instance.html"> 10<link rel="import" href="/tracing/model/time_to_object_instance_map.html"> 11<link rel="import" href="/tracing/base/utils.html"> 12<link rel="import" href="/tracing/base/range.html"> 13<link rel="import" href="/tracing/base/sorted_array_utils.html"> 14 15<script> 16'use strict'; 17 18/** 19 * @fileoverview Provides the ObjectCollection class. 20 */ 21tr.exportTo('tr.model', function() { 22 var ObjectInstance = tr.model.ObjectInstance; 23 var ObjectSnapshot = tr.model.ObjectSnapshot; 24 25 /** 26 * A collection of object instances and their snapshots, accessible by id and 27 * time, or by object name. 28 * 29 * @constructor 30 */ 31 function ObjectCollection(parent) { 32 tr.model.EventContainer.call(this); 33 this.parent = parent; 34 // scope -> {id -> TimeToObjectInstanceMap} 35 this.instanceMapsByScopedId_ = {}; 36 this.instancesByTypeName_ = {}; 37 this.createObjectInstance_ = this.createObjectInstance_.bind(this); 38 } 39 40 ObjectCollection.prototype = { 41 __proto__: tr.model.EventContainer.prototype, 42 43 iterateAllChildEventContainers: function(callback, opt_this) { 44 }, 45 46 iterateAllEventsInThisContainer: function(eventTypePredicate, 47 callback, opt_this) { 48 var bI = !!eventTypePredicate.call(opt_this, ObjectInstance); 49 var bS = !!eventTypePredicate.call(opt_this, ObjectSnapshot); 50 if (bI === false && bS === false) 51 return; 52 this.iterObjectInstances(function(instance) { 53 if (bI) 54 callback.call(opt_this, instance); 55 if (bS) 56 instance.snapshots.forEach(callback, opt_this); 57 }, opt_this); 58 }, 59 60 createObjectInstance_: function( 61 parent, scopedId, category, name, creationTs, opt_baseTypeName) { 62 var constructor = tr.model.ObjectInstance.getConstructor( 63 category, name); 64 var instance = new constructor( 65 parent, scopedId, category, name, creationTs, opt_baseTypeName); 66 var typeName = instance.typeName; 67 var instancesOfTypeName = this.instancesByTypeName_[typeName]; 68 if (!instancesOfTypeName) { 69 instancesOfTypeName = []; 70 this.instancesByTypeName_[typeName] = instancesOfTypeName; 71 } 72 instancesOfTypeName.push(instance); 73 return instance; 74 }, 75 76 getOrCreateInstanceMap_: function(scopedId) { 77 var dict; 78 if (scopedId.scope in this.instanceMapsByScopedId_) { 79 dict = this.instanceMapsByScopedId_[scopedId.scope]; 80 } else { 81 dict = {}; 82 this.instanceMapsByScopedId_[scopedId.scope] = dict; 83 } 84 var instanceMap = dict[scopedId.id]; 85 if (instanceMap) 86 return instanceMap; 87 instanceMap = new tr.model.TimeToObjectInstanceMap( 88 this.createObjectInstance_, this.parent, scopedId); 89 dict[scopedId.id] = instanceMap; 90 return instanceMap; 91 }, 92 93 idWasCreated: function(scopedId, category, name, ts) { 94 var instanceMap = this.getOrCreateInstanceMap_(scopedId); 95 return instanceMap.idWasCreated(category, name, ts); 96 }, 97 98 addSnapshot: function( 99 scopedId, category, name, ts, args, opt_baseTypeName) { 100 var instanceMap = this.getOrCreateInstanceMap_(scopedId); 101 var snapshot = instanceMap.addSnapshot( 102 category, name, ts, args, opt_baseTypeName); 103 if (snapshot.objectInstance.category != category) { 104 var msg = 'Added snapshot name=' + name + ' with cat=' + category + 105 ' impossible. It instance was created/snapshotted with cat=' + 106 snapshot.objectInstance.category + ' name=' + 107 snapshot.objectInstance.name; 108 throw new Error(msg); 109 } 110 if (opt_baseTypeName && 111 snapshot.objectInstance.baseTypeName != opt_baseTypeName) { 112 throw new Error('Could not add snapshot with baseTypeName=' + 113 opt_baseTypeName + '. It ' + 114 'was previously created with name=' + 115 snapshot.objectInstance.baseTypeName); 116 } 117 if (snapshot.objectInstance.name != name) { 118 throw new Error('Could not add snapshot with name=' + name + '. It ' + 119 'was previously created with name=' + 120 snapshot.objectInstance.name); 121 } 122 return snapshot; 123 }, 124 125 idWasDeleted: function(scopedId, category, name, ts) { 126 var instanceMap = this.getOrCreateInstanceMap_(scopedId); 127 var deletedInstance = instanceMap.idWasDeleted(category, name, ts); 128 if (!deletedInstance) 129 return; 130 if (deletedInstance.category != category) { 131 var msg = 'Deleting object ' + deletedInstance.name + 132 ' with a different category ' + 133 'than when it was created. It previous had cat=' + 134 deletedInstance.category + ' but the delete command ' + 135 'had cat=' + category; 136 throw new Error(msg); 137 } 138 if (deletedInstance.baseTypeName != name) { 139 throw new Error('Deletion requested for name=' + 140 name + ' could not proceed: ' + 141 'An existing object with baseTypeName=' + 142 deletedInstance.baseTypeName + ' existed.'); 143 } 144 }, 145 146 autoDeleteObjects: function(maxTimestamp) { 147 tr.b.iterItems(this.instanceMapsByScopedId_, function(scope, imapById) { 148 tr.b.iterItems(imapById, function(id, i2imap) { 149 var lastInstance = i2imap.lastInstance; 150 if (lastInstance.deletionTs != Number.MAX_VALUE) 151 return; 152 i2imap.idWasDeleted( 153 lastInstance.category, lastInstance.name, maxTimestamp); 154 // idWasDeleted will cause lastInstance.deletionTsWasExplicit to be 155 // set to true. Unset it here. 156 lastInstance.deletionTsWasExplicit = false; 157 }); 158 }); 159 }, 160 161 getObjectInstanceAt: function(scopedId, ts) { 162 var instanceMap; 163 if (scopedId.scope in this.instanceMapsByScopedId_) 164 instanceMap = this.instanceMapsByScopedId_[scopedId.scope][scopedId.id]; 165 if (!instanceMap) 166 return undefined; 167 return instanceMap.getInstanceAt(ts); 168 }, 169 170 getSnapshotAt: function(scopedId, ts) { 171 var instance = this.getObjectInstanceAt(scopedId, ts); 172 if (!instance) 173 return undefined; 174 return instance.getSnapshotAt(ts); 175 }, 176 177 iterObjectInstances: function(iter, opt_this) { 178 opt_this = opt_this || this; 179 tr.b.iterItems(this.instanceMapsByScopedId_, function(scope, imapById) { 180 tr.b.iterItems(imapById, function(id, i2imap) { 181 i2imap.instances.forEach(iter, opt_this); 182 }); 183 }); 184 }, 185 186 getAllObjectInstances: function() { 187 var instances = []; 188 this.iterObjectInstances(function(i) { instances.push(i); }); 189 return instances; 190 }, 191 192 getAllInstancesNamed: function(name) { 193 return this.instancesByTypeName_[name]; 194 }, 195 196 getAllInstancesByTypeName: function() { 197 return this.instancesByTypeName_; 198 }, 199 200 preInitializeAllObjects: function() { 201 this.iterObjectInstances(function(instance) { 202 instance.preInitialize(); 203 }); 204 }, 205 206 initializeAllObjects: function() { 207 this.iterObjectInstances(function(instance) { 208 instance.initialize(); 209 }); 210 }, 211 212 initializeInstances: function() { 213 this.iterObjectInstances(function(instance) { 214 instance.initialize(); 215 }); 216 }, 217 218 updateBounds: function() { 219 this.bounds.reset(); 220 this.iterObjectInstances(function(instance) { 221 instance.updateBounds(); 222 this.bounds.addRange(instance.bounds); 223 }, this); 224 }, 225 226 shiftTimestampsForward: function(amount) { 227 this.iterObjectInstances(function(instance) { 228 instance.shiftTimestampsForward(amount); 229 }); 230 }, 231 232 addCategoriesToDict: function(categoriesDict) { 233 this.iterObjectInstances(function(instance) { 234 categoriesDict[instance.category] = true; 235 }); 236 } 237 }; 238 239 return { 240 ObjectCollection: ObjectCollection 241 }; 242}); 243</script> 244