GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/file_chunk.cc Lines: 104 131 79.4 %
Date: 2019-02-03 02:48:13 Branches: 46 62 74.2 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#include "cvmfs_config.h"
6
#include "file_chunk.h"
7
8
#include <cassert>
9
10
#include "murmur.h"
11
#include "platform.h"
12
13
using namespace std;  // NOLINT
14
15
static inline uint32_t hasher_uint64t(const uint64_t &value) {
16
  return MurmurHash2(&value, sizeof(value), 0x07387a4f);
17
}
18
19
20
//------------------------------------------------------------------------------
21
22
23
10
unsigned FileChunkReflist::FindChunkIdx(const uint64_t off) {
24

10
  assert(list && (list->size() > 0));
25
10
  unsigned idx_low = 0;
26
10
  unsigned idx_high = list->size()-1;
27
10
  unsigned chunk_idx = idx_high/2;
28
35
  while (idx_low < idx_high) {
29
17
    if (static_cast<uint64_t>(list->AtPtr(chunk_idx)->offset()) > off) {
30
3
      assert(idx_high > 0);
31
3
      idx_high = chunk_idx - 1;
32
    } else {
33

14
      if ((chunk_idx == list->size() - 1) ||
34
          (static_cast<uint64_t>(list->AtPtr(chunk_idx + 1)->offset()) > off))
35
      {
36
2
        break;
37
      }
38
12
      idx_low = chunk_idx + 1;
39
    }
40
15
    chunk_idx = idx_low + (idx_high - idx_low) / 2;
41
  }
42
10
  return chunk_idx;
43
}
44
45
46
/**
47
 * Returns a consistent hash over hashes of the chunks. Used by libcvmfs.
48
 */
49
1
shash::Any FileChunkReflist::HashChunkList() {
50
1
  shash::Algorithms algo = list->AtPtr(0)->content_hash().algorithm;
51
1
  shash::ContextPtr ctx(algo);
52
1
  ctx.buffer = alloca(ctx.size);
53
1
  shash::Init(ctx);
54
3
  for (unsigned i = 0; i < list->size(); ++i) {
55
    shash::Update(list->AtPtr(i)->content_hash().digest,
56
                  shash::kDigestSizes[algo],
57
2
                  ctx);
58
  }
59
1
  shash::Any result(algo);
60
1
  shash::Final(ctx, &result);
61
1
  return result;
62
}
63
64
65
//------------------------------------------------------------------------------
66
67
68
32
void ChunkTables::InitLocks() {
69
  lock =
70
32
    reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t)));
71
32
  int retval = pthread_mutex_init(lock, NULL);
72
32
  assert(retval == 0);
73
74
4128
  for (unsigned i = 0; i < kNumHandleLocks; ++i) {
75
    pthread_mutex_t *m =
76
4096
      reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t)));
77
4096
    int retval = pthread_mutex_init(m, NULL);
78
4096
    assert(retval == 0);
79
4096
    handle_locks.PushBack(m);
80
  }
81
32
}
82
83
84
32
void ChunkTables::InitHashmaps() {
85
32
  handle2uniqino.Init(16, 0, hasher_uint64t);
86
32
  handle2fd.Init(16, 0, hasher_uint64t);
87
32
  inode2chunks.Init(16, 0, hasher_uint64t);
88
32
  inode2references.Init(16, 0, hasher_uint64t);
89
32
}
90
91
92
32
ChunkTables::ChunkTables() {
93
32
  next_handle = 2;
94
32
  version = kVersion;
95
32
  InitLocks();
96
32
  InitHashmaps();
97
}
98
99
100
32
ChunkTables::~ChunkTables() {
101
32
  pthread_mutex_destroy(lock);
102
32
  free(lock);
103
4128
  for (unsigned i = 0; i < kNumHandleLocks; ++i) {
104
4096
    pthread_mutex_destroy(handle_locks.At(i));
105
4096
    free(handle_locks.At(i));
106
  }
107
}
108
109
110
ChunkTables::ChunkTables(const ChunkTables &other) {
111
  version = kVersion;
112
  InitLocks();
113
  InitHashmaps();
114
  CopyFrom(other);
115
}
116
117
118
ChunkTables &ChunkTables::operator= (const ChunkTables &other) {
119
  if (&other == this)
120
    return *this;
121
122
  handle2uniqino.Clear();
123
  handle2fd.Clear();
124
  inode2chunks.Clear();
125
  inode2references.Clear();
126
  CopyFrom(other);
127
  return *this;
128
}
129
130
131
void ChunkTables::CopyFrom(const ChunkTables &other) {
132
  assert(version == other.version);
133
  next_handle = other.next_handle;
134
  inode2references = other.inode2references;
135
  inode2chunks = other.inode2chunks;
136
  handle2fd = other.handle2fd;
137
  handle2uniqino = other.handle2uniqino;
138
}
139
140
141
pthread_mutex_t *ChunkTables::Handle2Lock(const uint64_t handle) const {
142
  const uint32_t hash = hasher_uint64t(handle);
143
  const double bucket =
144
    static_cast<double>(hash) * static_cast<double>(kNumHandleLocks) /
145
    static_cast<double>((uint32_t)(-1));
146
  return handle_locks.At((uint32_t)bucket % kNumHandleLocks);
147
}
148
149
150
//------------------------------------------------------------------------------
151
152
153
8
SimpleChunkTables::SimpleChunkTables() {
154
  lock_ =
155
8
    reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t)));
156
8
  int retval = pthread_mutex_init(lock_, NULL);
157
8
  assert(retval == 0);
158
8
}
159
160
161
8
SimpleChunkTables::~SimpleChunkTables() {
162
9
  for (unsigned i = 0; i < fd_table_.size(); ++i) {
163
1
    delete fd_table_[i].chunk_reflist.list;
164
  }
165
8
  pthread_mutex_destroy(lock_);
166
8
  free(lock_);
167
8
}
168
169
170
8
int SimpleChunkTables::Add(FileChunkReflist chunks) {
171
8
  assert(chunks.list != NULL);
172
8
  OpenChunks new_entry;
173
8
  new_entry.chunk_reflist = chunks;
174
8
  new_entry.chunk_fd = new ChunkFd();
175
8
  unsigned i = 0;
176
8
  Lock();
177
22
  for (; i < fd_table_.size(); ++i) {
178
15
    if (fd_table_[i].chunk_reflist.list == NULL) {
179
1
      fd_table_[i] = new_entry;
180
1
      Unlock();
181
1
      return i;
182
    }
183
  }
184
7
  fd_table_.push_back(new_entry);
185
7
  Unlock();
186
7
  return i;
187
}
188
189
190
3
SimpleChunkTables::OpenChunks SimpleChunkTables::Get(int fd) {
191
3
  OpenChunks result;
192
3
  if (fd < 0)
193
1
    return result;
194
195
2
  unsigned idx = static_cast<unsigned>(fd);
196
2
  Lock();
197
2
  if (idx < fd_table_.size())
198
1
    result = fd_table_[idx];
199
2
  Unlock();
200
2
  return result;
201
}
202
203
204
9
void SimpleChunkTables::Release(int fd) {
205
9
  if (fd < 0)
206
1
    return;
207
208
8
  Lock();
209
8
  unsigned idx = static_cast<unsigned>(fd);
210
8
  if (idx >= fd_table_.size()) {
211
1
    Unlock();
212
1
    return;
213
  }
214
215
7
  delete fd_table_[idx].chunk_reflist.list;
216
7
  fd_table_[idx].chunk_reflist.list = NULL;
217
7
  fd_table_[idx].chunk_reflist.path.Assign("", 0);
218
7
  delete fd_table_[idx].chunk_fd;
219
7
  fd_table_[idx].chunk_fd = NULL;
220

20
  while (!fd_table_.empty() && (fd_table_.back().chunk_reflist.list == NULL)) {
221
6
    fd_table_.pop_back();
222
  }
223
7
  Unlock();
224

45
}