1 /*  $Id: gbload_util.cpp 440703 2014-07-16 15:38:41Z vasilche $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 *  Author: Michael Kimelman
27 *
28 *  File Description: GenBank Data loader
29 *
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <objtools/data_loaders/genbank/impl/gbload_util.hpp>
34 #include <objtools/data_loaders/genbank/gbloader.hpp>
35 #include <objtools/error_codes.hpp>
36 #include <objmgr/impl/handle_range.hpp>
37 #include <objmgr/objmgr_exception.hpp>
38 
39 
40 #define NCBI_USE_ERRCODE_X   Objtools_GB_Util
41 
42 BEGIN_NCBI_SCOPE
43 BEGIN_SCOPE(objects)
44 
45 //============================================================================
46 // Support Classes
47 //
48 
49 
50 /* =========================================================================== */
51 #if 0
52 //////////////////////////////////////////////////////////////////////////////
53 //
54 // CTimer
55 
56 CTimer::CTimer(void)
57     : m_RequestsDevider(0), m_Requests(0)
58 {
59     m_ReasonableRefreshDelay = 0;
60     m_LastCalibrated = m_Time= time(0);
61 }
62 
63 
64 time_t CTimer::Time(void)
65 {
66     if(--m_Requests>0)
67         return m_Time;
68     m_RequestsLock.Lock();
69     if(m_Requests<=0) {
70         time_t x = time(0);
71         if(x==m_Time) {
72             m_Requests += m_RequestsDevider + 1;
73             m_RequestsDevider = m_RequestsDevider*2 + 1;
74         } else {
75             m_Requests = m_RequestsDevider / ( x - m_Time );
76             m_Time=x;
77         }
78     }
79     m_RequestsLock.Unlock();
80     return m_Time;
81 }
82 
83 
84 void CTimer::Start(void)
85 {
86     m_TimerLock.Lock();
87     m_StartTime = Time();
88 }
89 
90 
91 void CTimer::Stop(void)
92 {
93     time_t x = Time() - m_StartTime; // test request timing in seconds
94     m_ReasonableRefreshDelay = 60 /*sec*/ *
95         (x==0 ? 5 /*min*/ : x*50 /* 50 min per sec of test request*/);
96     m_LastCalibrated = m_Time;
97     m_TimerLock.Unlock();
98 }
99 
100 
101 time_t CTimer::RetryTime(void)
102 {
103     return Time() +
104         (m_ReasonableRefreshDelay>0?m_ReasonableRefreshDelay:24*60*60);
105     /* 24 hours */
106 }
107 
108 
109 bool CTimer::NeedCalibration(void)
110 {
111     return
112         (m_ReasonableRefreshDelay==0) ||
113         (m_Time-m_LastCalibrated>100*m_ReasonableRefreshDelay);
114 }
115 #endif
116 
117 #if 0
118 void CRefresher::Reset(CTimer &timer)
119 {
120     m_RefreshTime = timer.RetryTime();
121 }
122 
123 
124 bool CRefresher::NeedRefresh(CTimer &timer) const
125 {
126     return timer.Time() > m_RefreshTime;
127 }
128 
129 
130 // MutexPool
131 //
132 
133 #if defined(NCBI_THREADS)
134 CMutexPool::CMutexPool()
135 {
136     m_size =0;
137     m_Locks=0;
138     spread =0;
139 }
140 
141 
142 void CMutexPool::SetSize(int size)
143 {
144     _VERIFY(m_size==0 && !m_Locks);
145     m_size = size;
146     m_Locks = new CMutex[m_size];
147     spread  = new int[m_size];
148     for ( int i = 0; i < m_size; ++i ) {
149         spread[i]=0;
150     }
151 }
152 
153 
154 CMutexPool::~CMutexPool(void)
155 {
156     delete [] m_Locks;
157     if ( spread )  {
158         for ( int i = 0; i < m_size; ++i ) {
159             GBLOG_POST_X(1, "PoolMutex " << i << " used "<< spread[i] << " times");
160         }
161     }
162     delete [] spread;
163 }
164 #else
165 CMutex CMutexPool::sm_Lock;
166 #endif
167 
168 /* =========================================================================== */
169 // CGBLGuard
170 //
171 CGBLGuard::CGBLGuard(TLMutex& lm,EState orig,const char *loc,int select)
172     : m_Locks(&lm),
173       m_Loc(loc),
174       m_orig(orig),
175       m_current(orig),
176       m_select(select)
177 {
178 }
179 
180 CGBLGuard::CGBLGuard(TLMutex &lm,const char *loc)
181     // assume orig=eNone, switch to e.Main in constructor
182     : m_Locks(&lm),
183       m_Loc(loc),
184       m_orig(eNone),
185       m_current(eNone),
186       m_select(-1)
187 {
188     Switch(eMain);
189 }
190 
191 CGBLGuard::CGBLGuard(CGBLGuard &g,const char *loc)
192     : m_Locks(g.m_Locks),
193       m_Loc(g.m_Loc),
194       m_orig(g.m_current),
195       m_current(g.m_current),
196       m_select(g.m_select)
197 {
198     if ( loc ) {
199         m_Loc = loc;
200     }
201     _VERIFY(m_Locks);
202 }
203 
204 CGBLGuard::~CGBLGuard()
205 {
206     Switch(m_orig);
207 }
208 
209 #if defined(NCBI_THREADS)
210 void CGBLGuard::Select(int s)
211 {
212     if ( m_current==eMain ) {
213         m_select=s;
214     }
215     _ASSERT(m_select==s);
216 }
217 
218 #define LOCK_POST(err_subcode, x) GBLOG_POST_X(err_subcode, x)
219 //#define LOCK_POST(err_subcode, x)
220 void CGBLGuard::MLock()
221 {
222     LOCK_POST(2, &m_Locks << ":: MainLock tried   @ " << m_Loc);
223     m_Locks->m_Lookup.Lock();
224     LOCK_POST(3, &m_Locks << ":: MainLock locked  @ " << m_Loc);
225 }
226 
227 void CGBLGuard::MUnlock()
228 {
229     LOCK_POST(4, &m_Locks << ":: MainLock unlocked@ " << m_Loc);
230     m_Locks->m_Lookup.Unlock();
231 }
232 
233 void CGBLGuard::PLock()
234 {
235     _ASSERT(m_select>=0);
236     LOCK_POST(5, &m_Locks << ":: Pool["<< setw(2) << m_select << "] tried   @ "
237                  << m_Loc);
238     m_Locks->m_Pool.GetMutex(m_select).Lock();
239     LOCK_POST(6, &m_Locks << ":: Pool["<< setw(2) << m_select << "] locked  @ "
240                  << m_Loc);
241 }
242 
243 void CGBLGuard::PUnlock()
244 {
245     _ASSERT(m_select>=0);
246     LOCK_POST(7, &m_Locks << ":: Pool["<< setw(2) << m_select << "] unlocked@ "
247                  << m_Loc);
248     m_Locks->m_Pool.GetMutex(m_select).Unlock();
249 }
250 
251 void CGBLGuard::Switch(EState newstate)
252 {
253     if(newstate==m_current) return;
254     switch(newstate) {
255     case eNone:
256         if ( m_current!=eMain ) {
257             Switch(eMain);
258         }
259         _ASSERT(m_current==eMain);
260         //LOCK_POST(8, &m_Locks << ":: switch 'main' to 'none'");
261         MUnlock();
262         m_current=eNone;
263         return;
264 
265     case eBoth:
266         if ( m_current!=eMain ) {
267             Switch(eMain);
268         }
269         _ASSERT(m_current==eMain);
270         //LOCK_POST(9, &m_Locks << ":: switch 'main' to 'both'");
271         if ( m_Locks->m_SlowTraverseMode>0 ) {
272             PLock();
273         }
274         m_current=eBoth;
275         return;
276 
277     case eLocal:
278         if ( m_current!=eBoth ) {
279             Switch(eBoth);
280         }
281         _ASSERT(m_current==eBoth);
282         //LOCK_POST(10, &m_Locks << ":: switch 'both' to 'local'");
283         if(m_Locks->m_SlowTraverseMode==0) {
284             PLock();
285         }
286         try {
287             m_Locks->m_SlowTraverseMode++;
288             MUnlock();
289         }
290         catch( exception& ) {
291             m_Locks->m_SlowTraverseMode--;
292             if(m_Locks->m_SlowTraverseMode==0) {
293                 PUnlock();
294             }
295             throw;
296         }
297         m_current=eLocal;
298         return;
299     case eMain:
300         switch(m_current) {
301         case eNone:
302             m_select=-1;
303             //LOCK_POST(11, &m_Locks << ":: switch 'none' to 'main'");
304             MLock();
305             m_current=eMain;
306             return;
307         case eBoth:
308             //LOCK_POST(12, &m_Locks << ":: switch 'both' to 'main'");
309             if(m_Locks->m_SlowTraverseMode>0) {
310                 PUnlock();
311             }
312             m_select=-1;
313             m_current=eMain;
314             return;
315         case eLocal:
316             //LOCK_POST(13, &m_Locks << ":: switch 'local' to 'none2main'");
317             PUnlock();
318             m_current=eNoneToMain;
319         case eNoneToMain:
320             //LOCK_POST(14, &m_Locks << ":: switch 'none2main' to 'main'");
321             MLock();
322             m_Locks->m_SlowTraverseMode--;
323             m_select=-1;
324             m_current=eMain;
325             return;
326         default:
327             break;
328         }
329     default:
330         break;
331     }
332     NCBI_THROW(CLoaderException, eOtherError,
333         "CGBLGuard::Switch - state desynchronized");
334 }
335 #endif // if(NCBI_THREADS)
336 
337 #endif
338 
339 END_SCOPE(objects)
340 END_NCBI_SCOPE
341