source: trunk/libtransmission/completion.c

Last change on this file was 14241, checked in by jordan, 7 years ago

Copyedit the license's revised text: (1) remove unnecessary repitition use of the word 'license' from the top of the header and source files (2) add the standard 'we hope it's useful, but no warranty' clause to COPYING (3) make explicit that linking OpenSSL is allowed (see https://people.gnome.org/~markmc/openssl-and-the-gpl.html for background) (4) sync the Qt and GTK+ clients' license popups with COPYING's revised text

  • Property svn:keywords set to Date Rev Author Id
File size: 7.8 KB
Line 
1/*
2 * This file Copyright (C) 2009-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: completion.c 14241 2014-01-21 03:10:30Z mikedld $
8 */
9
10#include <assert.h>
11
12#include "transmission.h"
13#include "completion.h"
14#include "torrent.h"
15#include "utils.h"
16
17/***
18****
19***/
20
21static void
22tr_cpReset (tr_completion * cp)
23{
24  cp->sizeNow = 0;
25  cp->sizeWhenDoneIsDirty = true;
26  cp->haveValidIsDirty = true;
27  tr_bitfieldSetHasNone (&cp->blockBitfield);
28}
29
30void
31tr_cpConstruct (tr_completion * cp, tr_torrent * tor)
32{
33  cp->tor = tor;
34  tr_bitfieldConstruct (&cp->blockBitfield, tor->blockCount);
35  tr_cpReset (cp);
36}
37
38void
39tr_cpBlockInit (tr_completion * cp, const tr_bitfield * b)
40{
41  tr_cpReset (cp);
42
43  /* set blockBitfield */
44  tr_bitfieldSetFromBitfield (&cp->blockBitfield, b);
45
46  /* set sizeNow */
47  cp->sizeNow = tr_bitfieldCountTrueBits (&cp->blockBitfield);
48  assert (cp->sizeNow <= cp->tor->blockCount);
49  cp->sizeNow *= cp->tor->blockSize;
50  if (tr_bitfieldHas (b, cp->tor->blockCount-1))
51    cp->sizeNow -= (cp->tor->blockSize - cp->tor->lastBlockSize);
52
53  assert (cp->sizeNow <= cp->tor->info.totalSize);
54}
55
56/***
57****
58***/
59
60tr_completeness
61tr_cpGetStatus (const tr_completion * cp)
62{
63  if (tr_cpHasAll (cp))
64    return TR_SEED;
65
66  if (!tr_torrentHasMetadata (cp->tor))
67    return TR_LEECH;
68
69  if (cp->sizeNow == tr_cpSizeWhenDone (cp))
70    return TR_PARTIAL_SEED;
71
72  return TR_LEECH;
73}
74
75void
76tr_cpPieceRem (tr_completion *  cp, tr_piece_index_t piece)
77{
78  tr_block_index_t i, f, l;
79  const tr_torrent * tor = cp->tor;
80
81  tr_torGetPieceBlockRange (cp->tor, piece, &f, &l);
82
83  for (i=f; i<=l; ++i)
84    if (tr_cpBlockIsComplete (cp, i))
85      cp->sizeNow -= tr_torBlockCountBytes (tor, i);
86
87  cp->haveValidIsDirty = true;
88  cp->sizeWhenDoneIsDirty = true;
89  tr_bitfieldRemRange (&cp->blockBitfield, f, l+1);
90}
91
92void
93tr_cpPieceAdd (tr_completion * cp, tr_piece_index_t piece)
94{
95  tr_block_index_t i, f, l;
96  tr_torGetPieceBlockRange (cp->tor, piece, &f, &l);
97
98  for (i=f; i<=l; ++i)
99    tr_cpBlockAdd (cp, i);
100}
101
102void
103tr_cpBlockAdd (tr_completion * cp, tr_block_index_t block)
104{
105  const tr_torrent * tor = cp->tor;
106
107  if (!tr_cpBlockIsComplete (cp, block))
108    {
109      const tr_piece_index_t piece = tr_torBlockPiece (cp->tor, block);
110
111      tr_bitfieldAdd (&cp->blockBitfield, block);
112      cp->sizeNow += tr_torBlockCountBytes (tor, block);
113
114      cp->haveValidIsDirty = true;
115      cp->sizeWhenDoneIsDirty |= tor->info.pieces[piece].dnd;
116    }
117}
118
119/***
120****
121***/
122
123uint64_t
124tr_cpHaveValid (const tr_completion * ccp)
125{
126  if (ccp->haveValidIsDirty)
127    {
128      tr_piece_index_t i;
129      uint64_t size = 0;
130      tr_completion * cp = (tr_completion *) ccp; /* mutable */
131      const tr_torrent * tor = ccp->tor;
132      const tr_info * info = &tor->info;
133
134      for (i=0; i<info->pieceCount; ++i)
135        if (tr_cpPieceIsComplete (ccp, i))
136          size += tr_torPieceCountBytes (tor, i);
137
138      cp->haveValidLazy = size;
139      cp->haveValidIsDirty = false;
140    }
141
142  return ccp->haveValidLazy;
143}
144
145uint64_t
146tr_cpSizeWhenDone (const tr_completion * ccp)
147{
148  if (ccp->sizeWhenDoneIsDirty)
149    {
150      uint64_t size = 0;
151      const tr_torrent * tor = ccp->tor;
152      const tr_info * inf = tr_torrentInfo (tor);
153      tr_completion * cp = (tr_completion *) ccp; /* mutable */
154
155      if (tr_cpHasAll (ccp))
156        {
157          size = inf->totalSize;
158        }
159      else
160        {
161          tr_piece_index_t p;
162
163          for (p=0; p<inf->pieceCount; ++p)
164            {
165              uint64_t n = 0;
166              const uint64_t pieceSize = tr_torPieceCountBytes (tor, p);
167
168              if (!inf->pieces[p].dnd)
169                {
170                  n = pieceSize;
171                }
172              else
173                {
174                  tr_block_index_t f, l;
175                  tr_torGetPieceBlockRange (cp->tor, p, &f, &l);
176
177                  n = tr_bitfieldCountRange (&cp->blockBitfield, f, l+1);
178                  n *= cp->tor->blockSize;
179                  if (l == (cp->tor->blockCount-1) && tr_bitfieldHas (&cp->blockBitfield, l))
180                    n -= (cp->tor->blockSize - cp->tor->lastBlockSize);
181                }
182
183              assert (n <= tr_torPieceCountBytes (tor, p));
184              size += n;
185            }
186        }
187
188      assert (size <= inf->totalSize);
189      assert (size >= cp->sizeNow);
190
191      cp->sizeWhenDoneLazy = size;
192      cp->sizeWhenDoneIsDirty = false;
193    }
194
195  return ccp->sizeWhenDoneLazy;
196}
197
198uint64_t
199tr_cpLeftUntilDone (const tr_completion * cp)
200{
201  const uint64_t sizeWhenDone = tr_cpSizeWhenDone (cp);
202
203  assert (sizeWhenDone >= cp->sizeNow);
204
205  return sizeWhenDone - cp->sizeNow;
206}
207
208void
209tr_cpGetAmountDone (const tr_completion * cp, float * tab, int tabCount)
210{
211  int i;
212  const bool seed = tr_cpHasAll (cp);
213  const float interval = cp->tor->info.pieceCount / (float)tabCount;
214
215  for (i=0; i<tabCount; ++i)
216    {
217      if (seed)
218        {
219          tab[i] = 1.0f;
220        }
221      else
222        {
223          tr_block_index_t f, l;
224          const tr_piece_index_t piece = (tr_piece_index_t)i * interval;
225          tr_torGetPieceBlockRange (cp->tor, piece, &f, &l);
226          tab[i] = tr_bitfieldCountRange (&cp->blockBitfield, f, l+1) / (float)(l+1-f);
227        }
228    }
229}
230
231size_t
232tr_cpMissingBlocksInPiece (const tr_completion * cp, tr_piece_index_t piece)
233{
234  if (tr_cpHasAll (cp))
235    {
236      return 0;
237    }
238  else
239    {
240      tr_block_index_t f, l;
241      tr_torGetPieceBlockRange (cp->tor, piece, &f, &l);
242      return (l+1-f) - tr_bitfieldCountRange (&cp->blockBitfield, f, l+1);
243    }
244}
245
246size_t
247tr_cpMissingBytesInPiece (const tr_completion * cp, tr_piece_index_t piece)
248{
249  if (tr_cpHasAll (cp))
250    {
251      return 0;
252    }
253  else
254    {
255      size_t haveBytes = 0;
256      tr_block_index_t f, l;
257      const size_t pieceByteSize = tr_torPieceCountBytes (cp->tor, piece);
258      tr_torGetPieceBlockRange (cp->tor, piece, &f, &l);
259      if (f != l)
260        {
261          /* nb: we don't pass the usual l+1 here to tr_bitfieldCountRange ().
262             It's faster to handle the last block separately because its size
263             needs to be checked separately. */
264          haveBytes = tr_bitfieldCountRange (&cp->blockBitfield, f, l);
265          haveBytes *= cp->tor->blockSize;
266        }
267
268      if (tr_bitfieldHas (&cp->blockBitfield, l)) /* handle the last block */
269        haveBytes += tr_torBlockCountBytes (cp->tor, l);
270
271      assert (haveBytes <= pieceByteSize);
272      return pieceByteSize - haveBytes;
273    }
274}
275
276bool
277tr_cpFileIsComplete (const tr_completion * cp, tr_file_index_t i)
278{
279  if (cp->tor->info.files[i].length == 0)
280    {
281      return true;
282    }
283  else
284    {
285      tr_block_index_t f, l;
286      tr_torGetFileBlockRange (cp->tor, i, &f, &l);
287      return tr_bitfieldCountRange (&cp->blockBitfield, f, l+1) == (l+1-f);
288    }
289}
290
291void *
292tr_cpCreatePieceBitfield (const tr_completion * cp, size_t * byte_count)
293{
294  void * ret;
295  tr_piece_index_t n;
296  tr_bitfield pieces;
297
298  assert (tr_torrentHasMetadata (cp->tor));
299
300  n = cp->tor->info.pieceCount;
301  tr_bitfieldConstruct (&pieces, n);
302
303  if (tr_cpHasAll (cp))
304    {
305      tr_bitfieldSetHasAll (&pieces);
306    }
307  else if (!tr_cpHasNone (cp))
308    {
309      tr_piece_index_t i;
310      bool * flags = tr_new (bool, n);
311      for (i=0; i<n; ++i)
312        flags[i] = tr_cpPieceIsComplete (cp, i);
313      tr_bitfieldSetFromFlags (&pieces, flags, n);
314      tr_free (flags);
315    }
316
317  ret = tr_bitfieldGetRaw (&pieces, byte_count);
318  tr_bitfieldDestruct (&pieces);
319  return ret;
320}
321
322double
323tr_cpPercentComplete (const tr_completion * cp)
324{
325  const double ratio = tr_getRatio (cp->sizeNow, cp->tor->info.totalSize);
326
327  if ((int)ratio == TR_RATIO_NA)
328    return 0.0;
329  else if ((int)ratio == TR_RATIO_INF)
330    return 1.0;
331  else
332    return ratio;
333}
334
335double
336tr_cpPercentDone (const tr_completion * cp)
337{
338  const double ratio = tr_getRatio (cp->sizeNow, tr_cpSizeWhenDone (cp));
339  const int iratio = (int)ratio;
340  return ((iratio == TR_RATIO_NA) || (iratio == TR_RATIO_INF)) ? 0.0 : ratio;
341}
342
Note: See TracBrowser for help on using the repository browser.