1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: disposetimer.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "datalock.hxx"
35 #include "disposetimer.hxx"
36 #include "cachecontroller.hxx"
37 #include "configexcept.hxx"
39 #include <osl/diagnose.h>
44 //==========================================================================
46 //==========================================================================
49 void OTreeDisposeScheduler::scheduleCleanup(RequestOptions
const& _aOptions
)
51 OSL_ENSURE(_aOptions
.hasLocale(), "ERROR: OTreeDisposeScheduler: cannot handle complete user scheduling");
53 CFG_TRACE_INFO("Scheduling data cleanup for user '%s' with locale '%s'",
54 OUSTRING2ASCII(_aOptions
.getEntity()),
55 OUSTRING2ASCII(_aOptions
.getLocale()));
57 CFG_TRACE_INFO_NI("- Cleanup will be started in about %d seconds", int(m_aCleanupDelay
.getTimeValue().Seconds
));
59 TimeStamp aNewTime
= implGetCleanupTime(TimeStamp::getCurrentTime(), m_aCleanupDelay
);
60 OSL_ASSERT(!aNewTime
.isNever());
62 TimeStamp aScheduleTime
= implAddTask(_aOptions
, aNewTime
);
64 OSL_ASSERT(aScheduleTime
<= aNewTime
);
65 OSL_ASSERT(!aScheduleTime
.isNever());
67 implStartBefore(aNewTime
);
69 // -------------------------------------------------------------------------
73 bool equivalentOptions(RequestOptions
const& lhs
, RequestOptions
const& rhs
)
75 lessRequestOptions lessThan
;
76 return ! (lessThan(lhs
,rhs
) || lessThan(rhs
,lhs
));
78 // -------------------------------------------------------------------------
80 void OTreeDisposeScheduler::stopAndClearTasks()
82 CFG_TRACE_INFO("Cancelling all data cleanup tasks, Stopping Cleanup timer");
83 CFG_TRACE_INFO_NI("- %d cleanup tasks were pending", int(m_aAgenda
.size()) );
85 if (m_xTimer
.isValid())
86 m_xTimer
->dispose(); // just to be sure
90 // -------------------------------------------------------------------------
92 std::pair
<bool,RequestOptions
> OTreeDisposeScheduler::getTask(TimeStamp
const& _aActualTime
, TimeStamp
& _rNextTime
)
94 OSL_ASSERT( _rNextTime
.isNever() ); // internal contract, we set this only in the positive case
96 std::pair
<bool,RequestOptions
> aTask( false, RequestOptions() );
98 if (!m_aAgenda
.empty())
100 Agenda::iterator
const it
= m_aAgenda
.begin();
102 if (it
->first
<= _aActualTime
)
104 aTask
= std::make_pair(true,it
->second
);
109 if (!m_aAgenda
.empty())
111 Agenda::iterator
const it
= m_aAgenda
.begin();
113 _rNextTime
= it
->first
;
118 // -------------------------------------------------------------------------
120 void OTreeDisposeScheduler::Timer::onShot()
124 pParent
->onTimerShot();
126 // -------------------------------------------------------------------------
128 void OTreeDisposeScheduler::onTimerShot()
130 CFG_TRACE_INFO("Cleanup Timer invoked - executing dispose task");
132 TimeStamp aActualTime
= TimeStamp::getCurrentTime();
133 TimeStamp aNextTime
= implGetCleanupTime(aActualTime
, getCleanupInterval());
137 TimeStamp aNextDisposeTime
= runDisposer(aActualTime
);
139 if (aNextTime
< aNextDisposeTime
)
140 aNextTime
= aNextDisposeTime
;
143 catch (uno::Exception
& )
145 OSL_ENSURE(false, "ERROR: UNO Exception left a disposer");
147 catch (configuration::Exception
& )
149 OSL_ENSURE(false, "ERROR: configuration::Exception left a disposer");
153 OSL_ENSURE(false, "ERROR: Unknown Exception left a disposer");
156 OSL_ASSERT(UnoApiLock::isHeld());
157 implStartBefore(aNextTime
);
159 // -------------------------------------------------------------------------
161 // this really should be a member of the TreeManager (see TreeManager::disposeOne etc.)
162 TimeStamp
OTreeDisposeScheduler::runDisposer(TimeStamp
const& _aActualTime
)
164 TimeStamp aNextTime
= TimeStamp::never();
165 OSL_ASSERT(aNextTime
.isNever());
167 OSL_ASSERT(UnoApiLock::isHeld());
169 std::pair
<bool,RequestOptions
> aTask
= this->getTask( _aActualTime
, aNextTime
);
172 RequestOptions
& rTaskOptions
= aTask
.second
;
174 CFG_TRACE_INFO("Found cleanup task for user %s and locale %s",
175 OUSTRING2ASCII(rTaskOptions
.getEntity()),
176 OUSTRING2ASCII(rTaskOptions
.getLocale()));
178 rtl::Reference
<CacheLoadingAccess
> aCache
= m_rTreeManager
.m_aCacheMap
.get(rTaskOptions
);
181 CFG_TRACE_INFO_NI("- Found matching data container (TreeInfo) - collecting data");
183 std::vector
< rtl::Reference
<CacheLine
> > aDisposeList
;
185 TimeStamp aNextTaskTime
= aCache
->collectDisposeList(aDisposeList
, _aActualTime
, m_aCleanupDelay
);
187 CFG_TRACE_INFO_NI("- Found %d module trees to dispose", int(aDisposeList
.size()) );
189 if (!aNextTaskTime
.isNever())
191 OSL_ENSURE( !aCache
->isEmpty(), "ERROR: Empty TreeInfo returning finite dispose time");
193 // repost with new time
194 OSL_ASSERT(UnoApiLock::isHeld());
196 CFG_TRACE_INFO_NI("- Rescheduling current option set" );
198 aNextTime
= this->implAddTask(rTaskOptions
,aNextTaskTime
);
201 else if (aCache
->isEmpty())// may have been the last one - check that
203 // currently it is not possible to release options which are
204 // because it is not save to delete the info if another thread is running in
208 CFG_TRACE_INFO_NI("- Currently no more cleanup tasks for this options set" );
210 if (!aDisposeList
.empty())
212 CFG_TRACE_INFO_NI("- Closing %d modules", int(aDisposeList
.size()) );
213 m_rTreeManager
.closeModules(aDisposeList
,rTaskOptions
);
216 CFG_TRACE_INFO_NI("- No modules trees to dispose");
219 CFG_TRACE_INFO_NI("- No matching data container (TreeInfo) found - task is obsolete");
222 CFG_TRACE_INFO("No eligible task found - may reschedule");
226 // -------------------------------------------------------------------------
229 TimeStamp
getExpirationTime( vos::OTimer
const& aTimer
)
231 OSL_ENSURE(aTimer
.isTicking(), "Timer is already expired !");
233 // note: order ensures that result time may be earlier, but not later
234 TimeStamp
const now ( TimeStamp::getCurrentTime() );
235 TimeInterval
const left( aTimer
.getRemainingTime() );
236 TimeStamp
const expires
= now
+ left
;
241 // -------------------------------------------------------------------------
243 #if OSL_DEBUG_LEVEL > 0
245 void checkTimerStarted( vos::OTimer
const& aTimer
, TimeStamp
const& _aLimit
)
247 const TimeInterval
tolerance( vos::TTimeValue(1) ); // milliseconds
248 if (aTimer
.isTicking())
250 TimeStamp
const expires
= getExpirationTime(aTimer
);
251 TimeStamp
const limit
= _aLimit
+ tolerance
;
253 OSL_ENSURE(expires
<= limit
, "Timer does not expire within expected time (tolerance 1 ms) !");
254 // OSL_ENSURE(expires <= _aLimit, "Timer does not expire within expected time !");
255 OSL_ENSURE(aTimer
.isTicking(), "Timer just started already expired ?!");
259 OSL_ENSURE(false, "Timer just started is not ticking ?!");
264 // -------------------------------------------------------------------------
265 // should be called guarded only
266 void OTreeDisposeScheduler::implStartBefore(TimeStamp
const& _aTime
)
268 // check if we were cleared
269 if (!m_aAgenda
.empty() && !_aTime
.isNever())
271 if (!m_xTimer
->isTicking() || _aTime
< getExpirationTime(*m_xTimer
))
273 m_xTimer
->setAbsoluteTime(_aTime
.getTimeValue());
275 if (!m_xTimer
->isTicking()) m_xTimer
->start();
277 OSL_DEBUG_ONLY( checkTimerStarted(*m_xTimer
,_aTime
) );
279 CFG_TRACE_INFO_NI("- Cleanup timer running - next execution in %d seconds", int (m_xTimer
->getRemainingTime().Seconds
) );
280 CFG_TRACE_INFO_NI("- %d cleanup tasks are pending", int(m_aAgenda
.size()) );
285 CFG_TRACE_INFO_NI("- Stopped timer - no more open cleanup tasks");
288 // -------------------------------------------------------------------------
290 TimeStamp
OTreeDisposeScheduler::implAddTask(RequestOptions
const& _aOptions
, TimeStamp
const& _aTime
)
292 OSL_ASSERT(UnoApiLock::isHeld());
294 // try to insert after euivalent entries (but STL may ignore the hint)
295 Agenda::iterator where
= m_aAgenda
.upper_bound(_aTime
);
297 m_aAgenda
.insert(where
, Agenda::value_type(_aTime
,_aOptions
));
299 OSL_ASSERT(!m_aAgenda
.empty());
301 return m_aAgenda
.begin()->first
;
303 // -------------------------------------------------------------------------