1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2014 FUJITSU LIMITED
7    	 * Copyright (C) 2014 CERN (Switzerland)
8    	 *
9    	 * Author: Takanori Nakao <nakao.takanori@jp.fujitsu.com>
10   	 * Author: Takeshi Miyamae <miyamae.takeshi@jp.fujitsu.com>
11   	 * Author: Andreas-Joachim Peters <Andreas.Joachim.Peters@cern.ch>
12   	 *
13   	 *  This library is free software; you can redistribute it and/or
14   	 *  modify it under the terms of the GNU Lesser General Public
15   	 *  License as published by the Free Software Foundation; either
16   	 *  version 2.1 of the License, or (at your option) any later version.
17   	 *
18   	 */
19   	
20   	// -----------------------------------------------------------------------------
21   	#include "ErasureCodeShecTableCache.h"
22   	#include "common/debug.h"
23   	// -----------------------------------------------------------------------------
24   	using namespace std;
25   	
26   	// -----------------------------------------------------------------------------
27   	#define dout_context g_ceph_context
28   	#define dout_subsys ceph_subsys_osd
29   	#undef dout_prefix
30   	#define dout_prefix _tc_prefix(_dout)
31   	// -----------------------------------------------------------------------------
32   	
33   	// -----------------------------------------------------------------------------
34   	
35   	static ostream&
36   	_tc_prefix(std::ostream* _dout) {
37   	  return *_dout << "ErasureCodeShecTableCache: ";
38   	}
39   	
40   	// -----------------------------------------------------------------------------
41   	
(1) Event exn_spec_violation: An exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate().
Also see events: [fun_call_w_exception]
42   	ErasureCodeShecTableCache::~ErasureCodeShecTableCache()
43   	{
(2) Event fun_call_w_exception: Called function throws an exception of type "_ZN5boost16exception_detail10clone_implINS0_19error_info_injectorINSt8ios_base7failureB5cxx11EEEEE". [details]
Also see events: [exn_spec_violation]
44   	  std::lock_guard lock{codec_tables_guard};
45   	
46   	  // clean-up all allocated tables
47   	  {
48   	    codec_technique_tables_t::const_iterator ttables_it;
49   	    codec_tables_t::const_iterator tables_it;
50   	    codec_tables_t_::const_iterator tables_it_;
51   	    codec_tables_t__::const_iterator tables_it__;
52   	    codec_table_t::const_iterator table_it;
53   	
54   	    for (ttables_it = encoding_table.begin(); ttables_it != encoding_table.end(); ++ttables_it) {
55   	      for (tables_it = ttables_it->second.begin(); tables_it != ttables_it->second.end(); ++tables_it) {
56   	        for (tables_it_ = tables_it->second.begin(); tables_it_ != tables_it->second.end(); ++tables_it_) {
57   	          for (tables_it__ = tables_it_->second.begin(); tables_it__ != tables_it_->second.end(); ++tables_it__) {
58   	            for (table_it = tables_it__->second.begin(); table_it != tables_it__->second.end(); ++table_it) {
59   	              if (table_it->second) {
60   	                if (*(table_it->second)) {
61   	                  delete *(table_it->second);
62   	                }
63   	                delete table_it->second;
64   	              }
65   	            }
66   	          }
67   	        }
68   	      }
69   	    }
70   	  }
71   	
72   	  {
73   	    std::map<int, lru_map_t*>::const_iterator lru_map_it;
74   	    std::map<int, lru_list_t*>::const_iterator lru_list_it;
75   	
76   	    for (lru_map_it = decoding_tables.begin();
77   	         lru_map_it != decoding_tables.end();
78   	         ++lru_map_it) {
79   	      if (lru_map_it->second) {
80   	        delete lru_map_it->second;
81   	      }
82   	    }
83   	
84   	    for (lru_list_it = decoding_tables_lru.begin();
85   	         lru_list_it != decoding_tables_lru.end();
86   	         ++lru_list_it) {
87   	      if (lru_list_it->second) {
88   	        delete lru_list_it->second;
89   	      }
90   	    }
91   	  }
92   	}
93   	
94   	ErasureCodeShecTableCache::lru_map_t*
95   	ErasureCodeShecTableCache::getDecodingTables(int technique) {
96   	  // the caller must hold the guard mutex:
97   	  // => std::lock_guard lock{codec_tables_guard};
98   	
99   	  // create an lru_map if not yet allocated
100  	  if (!decoding_tables[technique]) {
101  	    decoding_tables[technique] = new lru_map_t;
102  	  }
103  	  return decoding_tables[technique];
104  	}
105  	
106  	ErasureCodeShecTableCache::lru_list_t*
107  	ErasureCodeShecTableCache::getDecodingTablesLru(int technique) {
108  	  // the caller must hold the guard mutex:
109  	  // => std::lock_guard lock{codec_tables_guard};
110  	
111  	  // create an lru_list if not yet allocated
112  	  if (!decoding_tables_lru[technique]) {
113  	    decoding_tables_lru[technique] = new lru_list_t;
114  	  }
115  	  return decoding_tables_lru[technique];
116  	}
117  	
118  	int**
119  	ErasureCodeShecTableCache::getEncodingTable(int technique, int k, int m, int c, int w)
120  	{
121  	  std::lock_guard lock{codec_tables_guard};
122  	  return getEncodingTableNoLock(technique,k,m,c,w);
123  	}
124  	
125  	// -----------------------------------------------------------------------------
126  	
127  	int**
128  	ErasureCodeShecTableCache::getEncodingTableNoLock(int technique, int k, int m, int c, int w)
129  	{
130  	  // create a pointer to store an encoding table address
131  	  if (!encoding_table[technique][k][m][c][w]) {
132  	    encoding_table[technique][k][m][c][w] = new (int*);
133  	    *encoding_table[technique][k][m][c][w] = 0;
134  	  }
135  	  return encoding_table[technique][k][m][c][w];
136  	}
137  	
138  	int*
139  	ErasureCodeShecTableCache::setEncodingTable(int technique, int k, int m, int c, int w, int* ec_in_table)
140  	{
141  	  std::lock_guard lock{codec_tables_guard};
142  	  int** ec_out_table = getEncodingTableNoLock(technique, k, m, c, w);
143  	  if (*ec_out_table) {
144  	    // somebody might have deposited this table in the meanwhile, so clean
145  	    // the input table and return the stored one
146  	    free (ec_in_table);
147  	    return *ec_out_table;
148  	  } else {
149  	    // we store the provided input table and return this one
150  	    *encoding_table[technique][k][m][c][w] = ec_in_table;
151  	    return ec_in_table;
152  	  }
153  	}
154  	
155  	ceph::mutex*
156  	ErasureCodeShecTableCache::getLock()
157  	{
158  	  return &codec_tables_guard;
159  	}
160  	
161  	uint64_t
162  	ErasureCodeShecTableCache::getDecodingCacheSignature(int k, int m, int c, int w,
163  	                                                     int *erased, int *avails) {
164  	  uint64_t signature = 0;
165  	  signature = (uint64_t)k;
166  	  signature |= ((uint64_t)m << 6);
167  	  signature |= ((uint64_t)c << 12);
168  	  signature |= ((uint64_t)w << 18);
169  	
170  	  for (int i=0; i < k+m; i++) {
171  	    signature |= ((uint64_t)(avails[i] ? 1 : 0) << (24+i));
172  	  }
173  	  for (int i=0; i < k+m; i++) {
174  	    signature |= ((uint64_t)(erased[i] ? 1 : 0) << (44+i));
175  	  }
176  	  return signature;
177  	}
178  	
179  	bool
180  	ErasureCodeShecTableCache::getDecodingTableFromCache(int* decoding_matrix,
181  	                                                     int* dm_row,
182  	                                                     int* dm_column,
183  	                                                     int* minimum,
184  	                                                     int technique,
185  	                                                     int k,
186  	                                                     int m,
187  	                                                     int c,
188  	                                                     int w,
189  	                                                     int* erased,
190  	                                                     int* avails) {
191  	  // --------------------------------------------------------------------------
192  	  // LRU decoding matrix cache
193  	  // --------------------------------------------------------------------------
194  	
195  	  uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails);
196  	  std::lock_guard lock{codec_tables_guard};
197  	
198  	  dout(20) << "[ get table    ] = " << signature << dendl;
199  	
200  	  // we try to fetch a decoding table from an LRU cache
201  	  lru_map_t* decode_tbls_map =
202  	    getDecodingTables(technique);
203  	
204  	  lru_list_t* decode_tbls_lru =
205  	    getDecodingTablesLru(technique);
206  	
207  	  lru_map_t::iterator decode_tbls_map_it = decode_tbls_map->find(signature);
208  	  if (decode_tbls_map_it == decode_tbls_map->end()) {
209  	    return false;
210  	  }
211  	
212  	  dout(20) << "[ cached table ] = " << signature << dendl;
213  	  // copy parameters out of the cache
214  	
215  	  memcpy(decoding_matrix,
216  	         decode_tbls_map_it->second.second.decoding_matrix,
217  	         k * k * sizeof(int));
218  	  memcpy(dm_row,
219  	         decode_tbls_map_it->second.second.dm_row,
220  	         k * sizeof(int));
221  	  memcpy(dm_column,
222  	         decode_tbls_map_it->second.second.dm_column,
223  	         k * sizeof(int));
224  	  memcpy(minimum,
225  	         decode_tbls_map_it->second.second.minimum,
226  	         (k+m) * sizeof(int));
227  	
228  	  // find item in LRU queue and push back
229  	  decode_tbls_lru->splice(decode_tbls_lru->end(),
230  	                          *decode_tbls_lru,
231  	                          decode_tbls_map_it->second.first);
232  	  return true;
233  	}
234  	
235  	void
236  	ErasureCodeShecTableCache::putDecodingTableToCache(int* decoding_matrix,
237  	                                                   int* dm_row,
238  	                                                   int* dm_column,
239  	                                                   int* minimum,
240  	                                                   int technique,
241  	                                                   int k,
242  	                                                   int m,
243  	                                                   int c,
244  	                                                   int w,
245  	                                                   int* erased,
246  	                                                   int* avails) {
247  	  // --------------------------------------------------------------------------
248  	  // LRU decoding matrix cache
249  	  // --------------------------------------------------------------------------
250  	
251  	  std::lock_guard lock{codec_tables_guard};
252  	
253  	  uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails);
254  	  dout(20) << "[ put table    ] = " << signature << dendl;
255  	
256  	  // we store a new table to the cache
257  	
258  	  //  bufferptr cachetable;
259  	
260  	  lru_map_t* decode_tbls_map =
261  	    getDecodingTables(technique);
262  	
263  	  lru_list_t* decode_tbls_lru =
264  	    getDecodingTablesLru(technique);
265  	
266  	  if (decode_tbls_map->count(signature)) {
267  	    dout(20) << "[ already on table ] = " << signature << dendl;
268  	
269  	    // find item in LRU queue and push back
270  	    decode_tbls_lru->splice(decode_tbls_lru->end(),
271  	                            *decode_tbls_lru,
272  	                            (*decode_tbls_map)[signature].first);
273  	    return;
274  	  }
275  	
276  	  // evt. shrink the LRU queue/map
277  	  if ((int)decode_tbls_lru->size() >=
278  	      ErasureCodeShecTableCache::decoding_tables_lru_length) {
279  	    dout(20) << "[ shrink lru   ] = " << signature << dendl;
280  	    // remove from map
281  	    decode_tbls_map->erase(decode_tbls_lru->front());
282  	    // remove from lru
283  	    decode_tbls_lru->pop_front();
284  	  }
285  	
286  	  {
287  	    dout(20) << "[ store table  ] = " << signature << dendl;
288  	
289  	    decode_tbls_lru->push_back(signature);
290  	
291  	    // allocate a new buffer
292  	    lru_list_t::iterator it_end = decode_tbls_lru->end();
293  	    --it_end;
294  	
295  	    lru_entry_t &map_value =
296  	      (*decode_tbls_map)[signature] =
297  	      std::make_pair(it_end, DecodingCacheParameter());
298  	    map_value.second.decoding_matrix = new int[k*k];
299  	    map_value.second.dm_row = new int[k];
300  	    map_value.second.dm_column = new int[k];
301  	    map_value.second.minimum = new int[k+m];
302  	
303  	    memcpy(map_value.second.decoding_matrix,
304  	           decoding_matrix,
305  	           k * k * sizeof(int));
306  	    memcpy(map_value.second.dm_row,
307  	           dm_row,
308  	           k * sizeof(int));
309  	    memcpy(map_value.second.dm_column,
310  	           dm_column,
311  	           k * sizeof(int));
312  	    memcpy(map_value.second.minimum,
313  	           minimum,
314  	           (k+m) * sizeof(int));
315  	
316  	    dout(20) << "[ cache size   ] = " << decode_tbls_lru->size() << dendl;
317  	  }
318  	}
319