GarbageCollector.cpp 6.73 KB
Newer Older
1
/*
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * The CERN Tape Archive (CTA) project
 * Copyright (C) 2015  CERN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

19
20
#include "GarbageCollector.hpp"
#include "RootEntry.hpp"
21
//#include "FIFO.hpp"
22
#include <algorithm>
23
24

namespace cta { namespace objectstore {
25
const size_t GarbageCollector::c_maxWatchedAgentsPerGC = 2;
26

27
GarbageCollector::GarbageCollector(Backend & os, Agent & agent): 
28
  m_objectStore(os), m_ourAgent(agent), m_agentRegister(os) {
29
30
31
  RootEntry re(m_objectStore);
  ScopedSharedLock reLock(re);
  re.fetch();
32
  m_agentRegister.setAddress(re.getAgentRegisterAddress());
33
34
35
36
  reLock.release();
  ScopedSharedLock arLock(m_agentRegister);
  m_agentRegister.fetch();
}
37

38
39
40
41
42
43
44
void GarbageCollector::runOnePass() {
  // Bump our own heart beat
  {
    ScopedExclusiveLock lock (m_ourAgent);
    m_ourAgent.fetch();
    m_ourAgent.bumpHeartbeat();
    m_ourAgent.commit();
45
  }
46
47
48
49
  trimGoneTargets();
  aquireTargets();
  checkHeartbeats();
}
50
  
51
52
53
54
55
56
57
58
59
60
void GarbageCollector::trimGoneTargets() {
  ScopedSharedLock arLock(m_agentRegister);
  m_agentRegister.fetch();
  arLock.release();
  std::list<std::string> agentList = m_agentRegister.getAgents();
  for (std::map<std::string, AgentWatchdog * >::iterator wa
        = m_watchedAgents.begin();
      wa != m_watchedAgents.end();) {
    if (agentList.end() == std::find(agentList.begin(), agentList.end(), wa->first)) {
      ScopedExclusiveLock oaLock(m_ourAgent);
61
      m_ourAgent.fetch();
62
      m_ourAgent.removeFromOwnership(wa->first);
63
      m_ourAgent.commit();
64
65
66
67
68
      oaLock.release();
      delete wa->second;
      m_watchedAgents.erase(wa++);
    } else {
      wa++;
69
70
    }
  }
71
}
72
  
73
74
75
76
77
78
79
80
void GarbageCollector::aquireTargets() {
  ScopedExclusiveLock arLock(m_agentRegister);
  m_agentRegister.fetch();
  // Get the list of untracked agents
  std::list<std::string> candidatesList = m_agentRegister.getUntrackedAgents();
  std::list<std::string>::const_iterator c = candidatesList.begin();
  // We can now take ownership of new agents, up to our max...
  // and we don't monitor ourselves!
81
82
  for (;m_watchedAgents.size() < c_maxWatchedAgentsPerGC
         && c!=candidatesList.end(); c++) {
83
    // We don't monitor ourselves
84
    if (*c != m_ourAgent.getAddressIfSet()) {
85
86
87
88
89
90
91
92
93
94
95
96
97
98
      // So we have a candidate we might want to monitor
      // First, check that the agent entry exists, and that ownership
      // is indeed pointing to the agent register
      Agent ag(*c, m_objectStore);
      if (!ag.exists()) {
        // This is a dangling pointer to a dead object:
        // remove it in the agentRegister.
        m_agentRegister.removeAgent(*c);
        continue;
      }
      ScopedExclusiveLock agLock(ag);
      ag.fetch();
      // Check that the actual owner is the agent register.
      // otherwise, it should not be listed as an agent to monitor
99
100
      if (ag.getOwner() != m_agentRegister.getAddressIfSet()) {
        m_agentRegister.trackAgent(ag.getAddressIfSet());
101
102
103
104
105
106
107
108
        agLock.release();
        continue;
      }
      // We are now interested in tracking this agent. So we will transfer its
      // ownership. We alredy have an exclusive lock on the agent.
      // Lock ours
      ScopedExclusiveLock oaLock(m_ourAgent);
      m_ourAgent.fetch();
109
      m_ourAgent.addToOwnership(ag.getAddressIfSet());
110
111
      m_ourAgent.commit();
      // We now have a pointer to the agent, we can make the ownership official
112
      ag.setOwner(m_ourAgent.getAddressIfSet());
113
114
115
      ag.commit();
      // And we can remove the now dangling pointer from the agent register
      // (we hold an exclusive lock all along)
116
      m_agentRegister.trackAgent(ag.getAddressIfSet());
117
      m_agentRegister.commit();
118
119
      // Agent is officially our, we can remove it from the untracked agent's
      // list
120
      m_agentRegister.trackAgent(ag.getAddressIfSet());
121
122
123
      // Agent is now officially ours, let's track it. We have the release the 
      // lock to the agent before constructing the watchdog, which builds
      // its own agent objects (and need to lock the object store representation)
124
      std::string agentName = ag.getAddressIfSet();
125
126
      double timeout=ag.getTimeout();
      agLock.release();      
127
128
      m_watchedAgents[agentName] =
        new AgentWatchdog(agentName, m_objectStore);
129
      m_watchedAgents[ag.getAddressIfSet()]->setTimeout(timeout);
130
    }
131
  }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  // Commit all the modifications to the agent register
  m_agentRegister.commit();
}
 
void GarbageCollector::checkHeartbeats() {
  // Check the heartbeats of the watched agents
  // We can still fail on many steps
  for (std::map<std::string, AgentWatchdog * >::iterator wa = m_watchedAgents.begin();
      wa != m_watchedAgents.end();) {
    // Get the heartbeat. Clean dead agents and remove references to them
    if (!wa->second->checkAlive()) {
      cleanupDeadAgent(wa->first);
      ScopedExclusiveLock oaLock(m_ourAgent);
      m_ourAgent.removeFromOwnership(wa->first);
      m_ourAgent.commit();
      delete wa->second;
      m_watchedAgents.erase(wa++);
    } else {
      wa++;
    }
  }
}

155
 void GarbageCollector::cleanupDeadAgent(const std::string & address) {
156
   // Check that we are still owners of the agent (sanity check).
157
   Agent agent(address, m_objectStore);
158
159
   ScopedExclusiveLock agLock(agent);
   agent.fetch();
160
   if (agent.getOwner() != m_ourAgent.getAddressIfSet()) {
161
162
163
     throw cta::exception::Exception("In GarbageCollector::cleanupDeadAgent: the ownership is not ours as expected");
   }
   // Return all objects owned by the agent to their respective backup owners
164
165
   auto ownedObjects = agent.getOwnershipList();
   for (auto obj = ownedObjects.begin(); obj!= ownedObjects.end(); obj++) {
166
167
     // Find the object
     GenericObject go(*obj, m_objectStore);
168
169
170
171
172
173
     // If the object does not exist, we're done.
     if (go.exists()) {
       ScopedExclusiveLock goLock(go);
       go.fetch();
       // Call GenericOpbject's garbage collect method, which in turn will
       // delegate to the object type's garbage collector.
174
       go.garbageCollect(goLock, address);
175
     }
176
177
178
     // In all cases, relinquish ownership for this object
     agent.removeFromOwnership(*obj);
     agent.commit();
179
   }
180
   // We now processed all the owned objects. We can delete the agent's entry
Eric Cano's avatar
Eric Cano committed
181
   agent.removeAndUnregisterSelf();
182
183
184
185
 }



186
}}