1 /*
2  *  swarmmanager.h
3  *
4  *  Arno: Classes for managing FileTransfers, that is, load them into memory or
5  *  release them when idle. This is called activation/deactivation.
6  *  This manager only manages FileTransfers, LiveTransfers are unmanaged,
7  *  i.e., always activated.
8  *
9  *  The activation/deactivation progress is hidden behind the swift API,
10  *  one should not use the SwarmManager directly.
11  *
12  *  ARNOTODO: tracker registration. The current implementation works if it
13  *  runs the primary seeder which is also the tracker for a swarm. Clients
14  *  that contact it will activate the swarm. Once a swarm no longer has
15  *  clients is can be deactivated (not currently implemented).
16  *
17  *  However, to be a non-primary seeder (i.e., not the tracker) a new
18  *  mechanism needs to be implemented that registers a swarm at a tracker
19  *  while being deactivated (activate only when clients come). In the present
20  *  swift design registration requires a Channel to be open to the tracker. This
21  *  design may need to be changed to allow for a BitTorrent register-for-30-mins
22  *  -and-disconnect style.
23  *
24  *  Current implementation will deactivate:
25  *  - when SetMaximumActiveSwarms() is exceeded (Thomas)
26  *  - when idle for more than SECONDS_UNUSED_UNTIL_SWARM_MAY_BE_DEACTIVATED.
27  *    Idle is when no Read(), Write() or DATA send or receive (Arno)
28  *    (see ContentTransfer::GlobalCleanCallback).
29  *
30  *  Note that FileTransfers with the zero-state implementation are actually
31  *  unloaded (=no FileTransfer object and no admin in SwarmManager) when idle,
32  *  see zerostate.cpp. This is orthogonal to idle deactivation.
33  *
34  *  Created by Thomas Schaap
35  *  Copyright 2009-2016 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved.
36  *
37  */
38 
39 #include <time.h>
40 #include <vector>
41 #include <list>
42 #include "hashtree.h"
43 
44 namespace swift
45 {
46     class SwarmManager;
47 
48     class SwarmData
49     {
50     protected:
51         int id_;
52         Sha1Hash rootHash_;
53         bool active_;
54         tint latestUse_;
55         bool stateToBeRemoved_;
56         bool contentToBeRemoved_;
57         FileTransfer* ft_;
58         std::string filename_;
59         std::string trackerurl_;
60         bool forceCheckDiskVSHash_;
61         popt_cont_int_prot_t contIntProtMethod_;
62         uint32_t chunkSize_;
63         bool zerostate_;
64         double cachedMaxSpeeds_[2];
65         bool cachedStorageReady_;
66         std::list<std::string> cachedStorageFilenames_;
67         uint64_t cachedSize_;
68         bool cachedIsComplete_;
69         uint64_t cachedComplete_;
70         std::string cachedOSPathName_;
71         std::list< std::pair<ProgressCallback, uint8_t> > cachedCallbacks_; //ARNOTODO: how does this work?
72         uint64_t cachedSeqComplete_; // Only for offset = 0
73         bool cached_;
74         std::string metadir_;
75     public:
76         SwarmData(const std::string filename, const Sha1Hash& rootHash, const std::string trackerurl,
77                   bool force_check_diskvshash, popt_cont_int_prot_t cipm, bool zerostate, uint32_t chunk_size,
78                   const std::string metadata="");
79         SwarmData(const SwarmData& sd);
80 
81         ~SwarmData();
82 
83         bool Touch(bool onlyifactive=true);
84         bool IsActive();
85         const Sha1Hash& RootHash();
86         int Id();
87         FileTransfer* GetTransfer(bool touch = true);
88         std::string& Filename();
89         std::string Tracker();
90         uint32_t ChunkSize();
91         bool IsZeroState();
92         std::string Metadir();
93 
94         // Find out cached values of non-active swarms
95         uint64_t Size();
96         bool IsComplete();
97         uint64_t Complete();
98         uint64_t SeqComplete(int64_t offset = 0);
99         std::string OSPathName();
100 
101         void SetMaxSpeed(data_direction_t ddir, double speed);
102         void AddProgressCallback(ProgressCallback cb, uint8_t agg);
103         void RemoveProgressCallback(ProgressCallback cb);
104 
105         friend class SwarmManager;
106     };
107 
108     class SwarmManager
109     {
110     protected:
111         SwarmManager();
112         ~SwarmManager();
113 
114 
115         // Singleton
116         static SwarmManager instance_;
117 
118         // Structures to keep track of all the swarms known to this manager
119         // That's two lists of swarms, indeed.
120         // The first allows very fast lookups
121         // - hash table (bucket is rootHash.bits[0]&63) containing lists ordered by rootHash (binary search possible)
122         // The second allows very fast access by numeric identifier (used in toplevel API)
123         // - just a vector with a new element for each new one, and a list of available indices
124         std::vector< std::vector<SwarmData*> > knownSwarms_;
125         std::vector<SwarmData*> swarmList_;
126         struct UnusedIndex {
127             int index;
128             tint since;
129         };
130         std::list<struct UnusedIndex> unusedIndices_;
131 
132         // Structures and functions for deferred removal of active swarms
133         struct event* eventCheckToBeRemoved_;
134         static void CheckSwarmsToBeRemovedCallback(evutil_socket_t fd, short events, void* arg);
135         void CheckSwarmsToBeRemoved();
136 
137         // Looking up swarms by rootHash, internal functions
138         int GetSwarmLocation(const std::vector<SwarmData*>& list, const Sha1Hash& rootHash);
139         SwarmData* GetSwarmData(const Sha1Hash& rootHash);
140 
141         // Internal activation method
142         SwarmData* ActivateSwarm(SwarmData* swarm);
143         void BuildSwarm(SwarmData* swarm);
144 
145         // Internal method to find the oldest swarm and deactivate it
146         bool DeactivateSwarm();
147         void DeactivateSwarm(SwarmData* swarm, int activeLoc);
148 
149         // Structures to keep track of active swarms
150         int maxActiveSwarms_;
151         int activeSwarmCount_;
152         std::vector<SwarmData*> activeSwarms_;
153 
154 #if SWARMMANAGER_ASSERT_INVARIANTS
155         void invariant();
156 #endif
157     public:
158         // Singleton
159         static SwarmManager& GetManager();
160 
161         // Add and remove swarms
162         SwarmData* AddSwarm(const std::string filename, const Sha1Hash& rootHash, const std::string trackerurl,
163                             bool force_check_diskvshash, popt_cont_int_prot_t cipm, bool zerostate, bool activate, uint32_t chunk_size,
164                             std::string metadir);
165         SwarmData* AddSwarm(const SwarmData& swarm, bool activate=true);
166         void RemoveSwarm(const Sha1Hash& rootHash, bool removeState = false, bool removeContent = false);
167 
168         // Find a swam, either by id or root hash
169         SwarmData* FindSwarm(int id);
170         SwarmData* FindSwarm(const Sha1Hash& rootHash);
171 
172         // Activate a swarm, so it can be used (not active swarms can't be read from/written to)
173         SwarmData* ActivateSwarm(const Sha1Hash& rootHash);
174         void DeactivateSwarm(const Sha1Hash& rootHash);
175 
176         // Manage maximum of active swarms
177         int GetMaximumActiveSwarms();
178         void SetMaximumActiveSwarms(int newMaxActiveSwarms);
179 
180         // Arno
181         tdlist_t GetTransferDescriptors();
182         // Arno: Called periodically to deactivate unused swarms, even if max not reached
183         void DeactivateIdleSwarms();
184 
185         class Iterator : public std::iterator<std::input_iterator_tag, SwarmData*>
186         {
187         protected:
188             int transfer_;
189         public:
190             Iterator();
191             Iterator(int transfer);
192             Iterator(const Iterator& other);
193             Iterator& operator++();
194             Iterator operator++(int);
195             bool operator==(const Iterator& other);
196             bool operator!=(const Iterator& other);
197             SwarmData* operator*();
198         };
199         friend class Iterator;
200         Iterator begin();
201         Iterator end();
202     };
203 }
204