1 /*
2  * cleaner.cc
3  *
4  *  Created on: 05.02.2011
5  *      Author: ed
6  */
7 
8 #include "debug.h"
9 #include "meta.h"
10 
11 #include "cleaner.h"
12 
13 #include "fileitem.h"
14 #include "acfg.h"
15 #include "caddrinfo.h"
16 #include "tcpconnect.h"
17 
18 #include <limits>
19 #include <cstring>
20 using namespace std;
21 
22 #define TERM_VAL (time_t(-1))
23 
24 namespace acng
25 {
26 
cleaner()27 cleaner::cleaner() : m_thr(0)
28 {
29 	Init();
30 }
Init()31 void cleaner::Init()
32 {
33 	for(auto&ts : stamps)
34 		ts=END_OF_TIME;
35 }
36 
~cleaner()37 cleaner::~cleaner()
38 {
39 }
40 
WorkLoop()41 void cleaner::WorkLoop()
42 {
43 	LOGSTART("cleaner::WorkLoop");
44 
45 	lockuniq g(this);
46 	for(;;)
47 	{
48 		// XXX: review the flow, is this always safe?
49 		eType what = TYPE_EXCONNS;
50 		time_t when = END_OF_TIME;
51 
52 		if(m_terminating)
53 			return;
54 
55 		// ok, who's next?
56 		for (unsigned i = 0; i < ETYPE_MAX; ++i)
57 		{
58 			if (stamps[i] < when)
59 			{
60 				what = (eType) i;
61 				when = stamps[i];
62 			}
63 		}
64 
65 		auto now=GetTime();
66 		if(when > now)
67 		{
68 			// work around buggy STL: add some years on top and hope it will be fixed then
69 			if(when == END_OF_TIME)
70 				when = now | 0x3ffffffe;
71 			wait_until(g, when, 111);
72 			continue;
73 		}
74 		stamps[what] = END_OF_TIME;
75 		g.unLock();
76 
77 		// good, do the work now
78 		time_t time_nextcand=END_OF_TIME;
79 		switch(what)
80 		{
81 		case TYPE_ACFGHOOKS:
82 			time_nextcand = cfg::BackgroundCleanup();
83 			USRDBG("acng::cfg:ExecutePostponed, nextRunTime now: " << time_nextcand);
84 			break;
85 
86 		case TYPE_EXCONNS:
87 			time_nextcand = g_tcp_con_factory.BackgroundCleanup();
88 			USRDBG("tcpconnect::ExpireCache, nextRunTime now: " << time_nextcand);
89 			break;
90 		case TYPE_EXFILEITEM:
91 			time_nextcand = fileItemMgmt::BackgroundCleanup();
92 			USRDBG("fileitem::DoDelayedUnregAndCheck, nextRunTime now: " << time_nextcand);
93 			break;
94 
95 		case ETYPE_MAX:
96 			return; // heh?
97 		}
98 
99 		if(time_nextcand <= now || time_nextcand < 1)
100 		{
101 			log::err(tSS() << "ERROR: looping bug candidate on " << (int) what
102 					<< ", value: " << time_nextcand);
103 			time_nextcand=GetTime()+60;
104 		}
105 
106 		g.reLock();
107 
108 		if (time_nextcand < stamps[what])
109 			stamps[what] = time_nextcand;
110 	};
111 }
112 
CleanerThreadAction(void * pVoid)113 inline void * CleanerThreadAction(void *pVoid)
114 {
115 	static_cast<cleaner*>(pVoid)->WorkLoop();
116 	return nullptr;
117 }
118 
ScheduleFor(time_t when,eType what)119 void cleaner::ScheduleFor(time_t when, eType what)
120 {
121 	setLockGuard;
122 	if(m_thr == 0)
123 	{
124 		Init();
125 		stamps[what] = when;
126 		pthread_create(&m_thr, nullptr, CleanerThreadAction, (void *)this);
127 	}
128 	else
129 	{
130 		// already scheduled for an earlier moment or
131 		// something else is pointed and this will come earlier anyhow
132 
133 		if(when > stamps[what])
134 			return;
135 
136 		stamps[what] = when;
137 		notifyAll();
138 	}
139 }
140 
Stop()141 void cleaner::Stop()
142 {
143 	{
144 		setLockGuard;
145 
146 		if(!m_thr)
147 			return;
148 
149 		m_terminating = true;
150 		notifyAll();
151 	}
152     pthread_join(m_thr, nullptr);
153 
154     setLockGuard;
155     m_thr = 0;
156 }
157 
dump_status()158 void cleaner::dump_status()
159 {
160 	setLockGuard;
161 	tSS msg;
162 	msg << "Cleanup schedule:\n";
163 	for(int i=0; i<cleaner::ETYPE_MAX; ++i)
164 		msg << stamps[i] << " (in " << (stamps[i]-GetTime()) << " seconds)\n";
165 	log::err(msg);
166 }
167 
168 
dump_handler(int)169 void dump_handler(int) {
170 	fileItemMgmt::dump_status();
171 	g_victor.dump_status();
172 	g_tcp_con_factory.dump_status();
173 	cfg::dump_trace();
174 }
175 
176 
177 }
178