VirtualBox

source: vbox/trunk/src/VBox/Main/BandwidthControlImpl.cpp@ 35128

Last change on this file since 35128 was 34588, checked in by vboxsync, 14 years ago

Burn fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "BandwidthControlImpl.h"
19#include "BandwidthGroupImpl.h"
20#include "MachineImpl.h"
21#include "Global.h"
22
23#include "AutoStateDep.h"
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <iprt/cpp/utils.h>
28
29// defines
30/////////////////////////////////////////////////////////////////////////////
31
32typedef std::list< ComObjPtr<BandwidthGroup> > BandwidthGroupList;
33
34struct BandwidthControl::Data
35{
36 Data(Machine *pMachine)
37 : pParent(pMachine)
38 { }
39
40 ~Data()
41 {};
42
43 Machine * const pParent;
44
45 // peer machine's bandwidth control
46 const ComObjPtr<BandwidthControl> pPeer;
47
48 // the following fields need special backup/rollback/commit handling,
49 // so they cannot be a part of BackupableData
50 Backupable<BandwidthGroupList> llBandwidthGroups;
51};
52
53// constructor / destructor
54/////////////////////////////////////////////////////////////////////////////
55
56HRESULT BandwidthControl::FinalConstruct()
57{
58 return S_OK;
59}
60
61void BandwidthControl::FinalRelease()
62{
63 uninit();
64}
65
66// public initializer/uninitializer for internal purposes only
67/////////////////////////////////////////////////////////////////////////////
68
69/**
70 * Initializes the bandwidth group object.
71 *
72 * @returns COM result indicator.
73 * @param aParent Pointer to our parent object.
74 * @param aName Name of the storage controller.
75 * @param aInstance Instance number of the storage controller.
76 */
77HRESULT BandwidthControl::init(Machine *aParent)
78{
79 LogFlowThisFunc(("aParent=%p\n", aParent));
80
81 ComAssertRet(aParent, E_INVALIDARG);
82
83 /* Enclose the state transition NotReady->InInit->Ready */
84 AutoInitSpan autoInitSpan(this);
85 AssertReturn(autoInitSpan.isOk(), E_FAIL);
86
87 m = new Data(aParent);
88
89 /* m->pPeer is left null */
90
91 m->llBandwidthGroups.allocate();
92
93 /* Confirm a successful initialization */
94 autoInitSpan.setSucceeded();
95
96 return S_OK;
97}
98
99/**
100 * Initializes the object given another object
101 * (a kind of copy constructor). This object shares data with
102 * the object passed as an argument.
103 *
104 * @note This object must be destroyed before the original object
105 * it shares data with is destroyed.
106 *
107 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
108 * reading if @a aReshare is false.
109 */
110HRESULT BandwidthControl::init(Machine *aParent,
111 BandwidthControl *aThat)
112{
113 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
114
115 ComAssertRet(aParent && aThat, E_INVALIDARG);
116
117 /* Enclose the state transition NotReady->InInit->Ready */
118 AutoInitSpan autoInitSpan(this);
119 AssertReturn(autoInitSpan.isOk(), E_FAIL);
120
121 m = new Data(aParent);
122
123 /* sanity */
124 AutoCaller thatCaller(aThat);
125 AssertComRCReturnRC(thatCaller.rc());
126
127 unconst(m->pPeer) = aThat;
128 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
129
130 /* create copies of all groups */
131 m->llBandwidthGroups.allocate();
132 BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
133 while (it != aThat->m->llBandwidthGroups->end())
134 {
135 ComObjPtr<BandwidthGroup> group;
136 group.createObject();
137 group->init(this, *it);
138 m->llBandwidthGroups->push_back(group);
139 ++ it;
140 }
141
142 /* Confirm successful initialization */
143 autoInitSpan.setSucceeded();
144
145 return S_OK;
146}
147
148/**
149 * Initializes the storage controller object given another guest object
150 * (a kind of copy constructor). This object makes a private copy of data
151 * of the original object passed as an argument.
152 */
153HRESULT BandwidthControl::initCopy(Machine *aParent, BandwidthControl *aThat)
154{
155 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
156
157 ComAssertRet(aParent && aThat, E_INVALIDARG);
158
159 /* Enclose the state transition NotReady->InInit->Ready */
160 AutoInitSpan autoInitSpan(this);
161 AssertReturn(autoInitSpan.isOk(), E_FAIL);
162
163 m = new Data(aParent);
164 /* m->pPeer is left null */
165
166 AutoCaller thatCaller(aThat);
167 AssertComRCReturnRC(thatCaller.rc());
168
169 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
170
171 /* create copies of all groups */
172 m->llBandwidthGroups.allocate();
173 BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
174 while (it != aThat->m->llBandwidthGroups->end())
175 {
176 ComObjPtr<BandwidthGroup> group;
177 group.createObject();
178 group->init(this, *it);
179 m->llBandwidthGroups->push_back(group);
180 ++ it;
181 }
182
183 /* Confirm a successful initialization */
184 autoInitSpan.setSucceeded();
185
186 return S_OK;
187}
188
189
190/**
191 * @note Locks this object for writing, together with the peer object
192 * represented by @a aThat (locked for reading).
193 */
194void BandwidthControl::copyFrom (BandwidthControl *aThat)
195{
196 AssertReturnVoid (aThat != NULL);
197
198 /* sanity */
199 AutoCaller autoCaller(this);
200 AssertComRCReturnVoid (autoCaller.rc());
201
202 /* sanity too */
203 AutoCaller thatCaller (aThat);
204 AssertComRCReturnVoid (thatCaller.rc());
205
206 /* even more sanity */
207 AutoAnyStateDependency adep(m->pParent);
208 AssertComRCReturnVoid (adep.rc());
209 /* Machine::copyFrom() may not be called when the VM is running */
210 AssertReturnVoid (!Global::IsOnline (adep.machineState()));
211
212 /* peer is not modified, lock it for reading (aThat is "master" so locked
213 * first) */
214 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
215 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
216
217 /* create private copies of all filters */
218 m->llBandwidthGroups.backup();
219 m->llBandwidthGroups->clear();
220 for (BandwidthGroupList::const_iterator it = aThat->m->llBandwidthGroups->begin();
221 it != aThat->m->llBandwidthGroups->end();
222 ++ it)
223 {
224 ComObjPtr<BandwidthGroup> group;
225 group.createObject();
226 group->initCopy (this, *it);
227 m->llBandwidthGroups->push_back (group);
228 }
229}
230
231/** @note Locks objects for writing! */
232void BandwidthControl::rollback()
233{
234 AutoCaller autoCaller(this);
235 AssertComRCReturnVoid(autoCaller.rc());
236
237 /* we need the machine state */
238 AutoAnyStateDependency adep(m->pParent);
239 AssertComRCReturnVoid(adep.rc());
240
241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
242
243 if (!m->llBandwidthGroups.isNull())
244 {
245 if (m->llBandwidthGroups.isBackedUp())
246 {
247 /* unitialize all new groups (absent in the backed up list). */
248 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
249 BandwidthGroupList *backedList = m->llBandwidthGroups.backedUpData();
250 while (it != m->llBandwidthGroups->end())
251 {
252 if ( std::find(backedList->begin(), backedList->end(), *it)
253 == backedList->end()
254 )
255 {
256 (*it)->uninit();
257 }
258 ++it;
259 }
260
261 /* restore the list */
262 m->llBandwidthGroups.rollback();
263 }
264
265 /* rollback any changes to groups after restoring the list */
266 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
267 while (it != m->llBandwidthGroups->end())
268 {
269 (*it)->rollback();
270 ++it;
271 }
272 }
273}
274
275void BandwidthControl::commit()
276{
277 bool commitBandwidthGroups = false;
278
279 if (m->llBandwidthGroups.isBackedUp())
280 {
281 m->llBandwidthGroups.commit();
282
283 if (m->pPeer)
284 {
285 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
286
287 /* Commit all changes to new controllers (this will reshare data with
288 * peers for those who have peers) */
289 BandwidthGroupList *newList = new BandwidthGroupList();
290 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
291 while (it != m->llBandwidthGroups->end())
292 {
293 (*it)->commit();
294
295 /* look if this group has a peer group */
296 ComObjPtr<BandwidthGroup> peer = (*it)->getPeer();
297 if (!peer)
298 {
299 /* no peer means the device is a newly created one;
300 * create a peer owning data this device share it with */
301 peer.createObject();
302 peer->init(m->pPeer, *it, true /* aReshare */);
303 }
304 else
305 {
306 /* remove peer from the old list */
307 m->pPeer->m->llBandwidthGroups->remove(peer);
308 }
309 /* and add it to the new list */
310 newList->push_back(peer);
311
312 ++it;
313 }
314
315 /* uninit old peer's controllers that are left */
316 it = m->pPeer->m->llBandwidthGroups->begin();
317 while (it != m->pPeer->m->llBandwidthGroups->end())
318 {
319 (*it)->uninit();
320 ++it;
321 }
322
323 /* attach new list of controllers to our peer */
324 m->pPeer->m->llBandwidthGroups.attach(newList);
325 }
326 else
327 {
328 /* we have no peer (our parent is the newly created machine);
329 * just commit changes to devices */
330 commitBandwidthGroups = true;
331 }
332 }
333 else
334 {
335 /* the list of groups itself is not changed,
336 * just commit changes to controllers themselves */
337 commitBandwidthGroups = true;
338 }
339
340 if (commitBandwidthGroups)
341 {
342 BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
343 while (it != m->llBandwidthGroups->end())
344 {
345 (*it)->commit();
346 ++it;
347 }
348 }
349}
350
351/**
352 * Uninitializes the instance and sets the ready flag to FALSE.
353 * Called either from FinalRelease() or by the parent when it gets destroyed.
354 */
355void BandwidthControl::uninit()
356{
357 LogFlowThisFunc(("\n"));
358
359 /* Enclose the state transition Ready->InUninit->NotReady */
360 AutoUninitSpan autoUninitSpan(this);
361 if (autoUninitSpan.uninitDone())
362 return;
363
364 // uninit all groups on the list (it's a standard std::list not an ObjectsList
365 // so we must uninit() manually)
366 for (BandwidthGroupList::iterator it = m->llBandwidthGroups->begin();
367 it != m->llBandwidthGroups->end();
368 ++it)
369 (*it)->uninit();
370
371 m->llBandwidthGroups.free();
372
373 unconst(m->pPeer) = NULL;
374 unconst(m->pParent) = NULL;
375
376 delete m;
377 m = NULL;
378}
379
380/**
381 * Returns a storage controller object with the given name.
382 *
383 * @param aName storage controller name to find
384 * @param aStorageController where to return the found storage controller
385 * @param aSetError true to set extended error info on failure
386 */
387HRESULT BandwidthControl::getBandwidthGroupByName(const Utf8Str &aName,
388 ComObjPtr<BandwidthGroup> &aBandwidthGroup,
389 bool aSetError /* = false */)
390{
391 AssertReturn(!aName.isEmpty(), E_INVALIDARG);
392
393 for (BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
394 it != m->llBandwidthGroups->end();
395 ++it)
396 {
397 if ((*it)->getName() == aName)
398 {
399 aBandwidthGroup = (*it);
400 return S_OK;
401 }
402 }
403
404 if (aSetError)
405 return setError(VBOX_E_OBJECT_NOT_FOUND,
406 tr("Could not find a bandwidth group named '%s'"),
407 aName.c_str());
408 return VBOX_E_OBJECT_NOT_FOUND;
409}
410
411STDMETHODIMP BandwidthControl::CreateBandwidthGroup(IN_BSTR aName, BandwidthGroupType_T aType, ULONG aMaxMbPerSec)
412{
413 AutoCaller autoCaller(this);
414 if (FAILED(autoCaller.rc())) return autoCaller.rc();
415
416 /* the machine needs to be mutable */
417 AutoMutableStateDependency adep(m->pParent);
418 if (FAILED(adep.rc())) return adep.rc();
419
420 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
421
422 /* try to find one with the name first. */
423 ComObjPtr<BandwidthGroup> group;
424
425 HRESULT rc = getBandwidthGroupByName(aName, group, false /* aSetError */);
426 if (SUCCEEDED(rc))
427 return setError(VBOX_E_OBJECT_IN_USE,
428 tr("Bandwidth group named '%ls' already exists"),
429 aName);
430
431 group.createObject();
432
433 rc = group->init(this, aName, aType, aMaxMbPerSec);
434 if (FAILED(rc)) return rc;
435
436 m->pParent->setModified(Machine::IsModified_BandwidthControl);
437 m->llBandwidthGroups.backup();
438 m->llBandwidthGroups->push_back(group);
439
440 return S_OK;
441}
442
443STDMETHODIMP BandwidthControl::DeleteBandwidthGroup(IN_BSTR aName)
444{
445 CheckComArgStrNotEmptyOrNull(aName);
446
447 AutoCaller autoCaller(this);
448 if (FAILED(autoCaller.rc())) return autoCaller.rc();
449
450 /* the machine needs to be mutable */
451 AutoMutableStateDependency adep(m->pParent);
452 if (FAILED(adep.rc())) return adep.rc();
453
454 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
455
456 ComObjPtr<BandwidthGroup> group;
457 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
458 if (FAILED(rc)) return rc;
459
460 if (group->getReferences() != 0)
461 return setError(VBOX_E_OBJECT_IN_USE,
462 tr("The bandwidth group '%ls' is still in use"), aName);
463
464 /* We can remove it now. */
465 m->pParent->setModified(Machine::IsModified_BandwidthControl);
466 m->llBandwidthGroups.backup();
467
468 group->unshare();
469
470 m->llBandwidthGroups->remove(group);
471
472 /* inform the direct session if any */
473 alock.leave();
474 //onStorageControllerChange(); @todo
475
476 return S_OK;
477}
478
479STDMETHODIMP BandwidthControl::COMGETTER(NumGroups)(ULONG *aGroups)
480{
481 CheckComArgNotNull(aGroups);
482
483 AutoCaller autoCaller(this);
484 if (FAILED(autoCaller.rc())) return autoCaller.rc();
485
486 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
487
488 *aGroups = m->llBandwidthGroups->size();
489
490 return S_OK;
491}
492
493STDMETHODIMP BandwidthControl::GetBandwidthGroup(IN_BSTR aName, IBandwidthGroup **aBandwidthGroup)
494{
495 CheckComArgStrNotEmptyOrNull(aName);
496
497 AutoCaller autoCaller(this);
498 if (FAILED(autoCaller.rc())) return autoCaller.rc();
499
500 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
501
502 ComObjPtr<BandwidthGroup> group;
503
504 HRESULT rc = getBandwidthGroupByName(aName, group, true /* aSetError */);
505 if (SUCCEEDED(rc))
506 group.queryInterfaceTo(aBandwidthGroup);
507
508 return rc;
509}
510
511STDMETHODIMP BandwidthControl::GetAllBandwidthGroups(ComSafeArrayOut(IBandwidthGroup *, aBandwidthGroups))
512{
513 CheckComArgOutSafeArrayPointerValid(aBandwidthGroups);
514
515 AutoCaller autoCaller(this);
516 if (FAILED(autoCaller.rc())) return autoCaller.rc();
517
518 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
519
520 SafeIfaceArray<IBandwidthGroup> collection (*m->llBandwidthGroups.data());
521 collection.detachTo(ComSafeArrayOutArg(aBandwidthGroups));
522
523 return S_OK;
524}
525
526HRESULT BandwidthControl::loadSettings(const settings::IoSettings &data)
527{
528 HRESULT rc = S_OK;
529
530 AutoCaller autoCaller(this);
531 AssertComRCReturnRC(autoCaller.rc());
532
533 for (settings::BandwidthGroupList::const_iterator it = data.llBandwidthGroups.begin();
534 it != data.llBandwidthGroups.end();
535 ++it)
536 {
537 const settings::BandwidthGroup &gr = *it;
538 rc = CreateBandwidthGroup(Bstr(gr.strName).raw(), gr.enmType, gr.cMaxMbPerSec);
539 if (FAILED(rc)) break;
540 }
541
542 return rc;
543}
544
545HRESULT BandwidthControl::saveSettings(settings::IoSettings &data)
546{
547 AutoCaller autoCaller(this);
548 if (FAILED(autoCaller.rc())) return autoCaller.rc();
549
550 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
551
552 data.llBandwidthGroups.clear();
553
554 for (BandwidthGroupList::const_iterator it = m->llBandwidthGroups->begin();
555 it != m->llBandwidthGroups->end();
556 ++it)
557 {
558 AutoWriteLock groupLock(*it COMMA_LOCKVAL_SRC_POS);
559 settings::BandwidthGroup group;
560
561 group.strName = (*it)->getName();
562 group.enmType = (*it)->getType();
563 group.cMaxMbPerSec = (*it)->getMaxMbPerSec();
564
565 data.llBandwidthGroups.push_back(group);
566 }
567
568 return S_OK;
569}
570
571Machine * BandwidthControl::getMachine() const
572{
573 return m->pParent;
574}
575
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette