// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2014 FUJITSU LIMITED * Copyright (C) 2014 CERN (Switzerland) * * Author: Takanori Nakao * Author: Takeshi Miyamae * Author: Andreas-Joachim Peters * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * */ // ----------------------------------------------------------------------------- #include "ErasureCodeShecTableCache.h" #include "common/debug.h" // ----------------------------------------------------------------------------- using namespace std; // ----------------------------------------------------------------------------- #define dout_context g_ceph_context #define dout_subsys ceph_subsys_osd #undef dout_prefix #define dout_prefix _tc_prefix(_dout) // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- static ostream& _tc_prefix(std::ostream* _dout) { return *_dout << "ErasureCodeShecTableCache: "; } // ----------------------------------------------------------------------------- ErasureCodeShecTableCache::~ErasureCodeShecTableCache() { Mutex::Locker lock(codec_tables_guard); // clean-up all allocated tables { codec_technique_tables_t::const_iterator ttables_it; codec_tables_t::const_iterator tables_it; codec_tables_t_::const_iterator tables_it_; codec_tables_t__::const_iterator tables_it__; codec_table_t::const_iterator table_it; for (ttables_it = encoding_table.begin(); ttables_it != encoding_table.end(); ++ttables_it) { for (tables_it = ttables_it->second.begin(); tables_it != ttables_it->second.end(); ++tables_it) { for (tables_it_ = tables_it->second.begin(); tables_it_ != tables_it->second.end(); ++tables_it_) { for (tables_it__ = tables_it_->second.begin(); tables_it__ != tables_it_->second.end(); ++tables_it__) { for (table_it = tables_it__->second.begin(); table_it != tables_it__->second.end(); ++table_it) { if (table_it->second) { if (*(table_it->second)) { delete *(table_it->second); } delete table_it->second; } } } } } } } { std::map::const_iterator lru_map_it; std::map::const_iterator lru_list_it; for (lru_map_it = decoding_tables.begin(); lru_map_it != decoding_tables.end(); ++lru_map_it) { if (lru_map_it->second) { delete lru_map_it->second; } } for (lru_list_it = decoding_tables_lru.begin(); lru_list_it != decoding_tables_lru.end(); ++lru_list_it) { if (lru_list_it->second) { delete lru_list_it->second; } } } } ErasureCodeShecTableCache::lru_map_t* ErasureCodeShecTableCache::getDecodingTables(int technique) { // the caller must hold the guard mutex: // => Mutex::Locker lock(codec_tables_guard); // create an lru_map if not yet allocated if (!decoding_tables[technique]) { decoding_tables[technique] = new lru_map_t; } return decoding_tables[technique]; } ErasureCodeShecTableCache::lru_list_t* ErasureCodeShecTableCache::getDecodingTablesLru(int technique) { // the caller must hold the guard mutex: // => Mutex::Locker lock(codec_tables_guard); // create an lru_list if not yet allocated if (!decoding_tables_lru[technique]) { decoding_tables_lru[technique] = new lru_list_t; } return decoding_tables_lru[technique]; } int** ErasureCodeShecTableCache::getEncodingTable(int technique, int k, int m, int c, int w) { Mutex::Locker lock(codec_tables_guard); return getEncodingTableNoLock(technique,k,m,c,w); } // ----------------------------------------------------------------------------- int** ErasureCodeShecTableCache::getEncodingTableNoLock(int technique, int k, int m, int c, int w) { // create a pointer to store an encoding table address if (!encoding_table[technique][k][m][c][w]) { encoding_table[technique][k][m][c][w] = new (int*); *encoding_table[technique][k][m][c][w] = 0; } return encoding_table[technique][k][m][c][w]; } int* ErasureCodeShecTableCache::setEncodingTable(int technique, int k, int m, int c, int w, int* ec_in_table) { Mutex::Locker lock(codec_tables_guard); int** ec_out_table = getEncodingTableNoLock(technique, k, m, c, w); if (*ec_out_table) { // somebody might have deposited this table in the meanwhile, so clean // the input table and return the stored one free (ec_in_table); return *ec_out_table; } else { // we store the provided input table and return this one *encoding_table[technique][k][m][c][w] = ec_in_table; return ec_in_table; } } Mutex* ErasureCodeShecTableCache::getLock() { return &codec_tables_guard; } uint64_t ErasureCodeShecTableCache::getDecodingCacheSignature(int k, int m, int c, int w, int *erased, int *avails) { uint64_t signature = 0; signature = (uint64_t)k; signature |= ((uint64_t)m << 6); signature |= ((uint64_t)c << 12); signature |= ((uint64_t)w << 18); for (int i=0; i < k+m; i++) { signature |= ((uint64_t)(avails[i] ? 1 : 0) << (24+i)); } for (int i=0; i < k+m; i++) { signature |= ((uint64_t)(erased[i] ? 1 : 0) << (44+i)); } return signature; } bool ErasureCodeShecTableCache::getDecodingTableFromCache(int* decoding_matrix, int* dm_row, int* dm_column, int* minimum, int technique, int k, int m, int c, int w, int* erased, int* avails) { // -------------------------------------------------------------------------- // LRU decoding matrix cache // -------------------------------------------------------------------------- uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails); Mutex::Locker lock(codec_tables_guard); dout(20) << "[ get table ] = " << signature << dendl; // we try to fetch a decoding table from an LRU cache lru_map_t* decode_tbls_map = getDecodingTables(technique); lru_list_t* decode_tbls_lru = getDecodingTablesLru(technique); lru_map_t::iterator decode_tbls_map_it = decode_tbls_map->find(signature); if (decode_tbls_map_it == decode_tbls_map->end()) { return false; } dout(20) << "[ cached table ] = " << signature << dendl; // copy parameters out of the cache memcpy(decoding_matrix, decode_tbls_map_it->second.second.decoding_matrix, k * k * sizeof(int)); memcpy(dm_row, decode_tbls_map_it->second.second.dm_row, k * sizeof(int)); memcpy(dm_column, decode_tbls_map_it->second.second.dm_column, k * sizeof(int)); memcpy(minimum, decode_tbls_map_it->second.second.minimum, (k+m) * sizeof(int)); // find item in LRU queue and push back decode_tbls_lru->splice(decode_tbls_lru->end(), *decode_tbls_lru, decode_tbls_map_it->second.first); return true; } void ErasureCodeShecTableCache::putDecodingTableToCache(int* decoding_matrix, int* dm_row, int* dm_column, int* minimum, int technique, int k, int m, int c, int w, int* erased, int* avails) { // -------------------------------------------------------------------------- // LRU decoding matrix cache // -------------------------------------------------------------------------- Mutex::Locker lock(codec_tables_guard); uint64_t signature = getDecodingCacheSignature(k, m, c, w, erased, avails); dout(20) << "[ put table ] = " << signature << dendl; // we store a new table to the cache // bufferptr cachetable; lru_map_t* decode_tbls_map = getDecodingTables(technique); lru_list_t* decode_tbls_lru = getDecodingTablesLru(technique); if (decode_tbls_map->count(signature)) { dout(20) << "[ already on table ] = " << signature << dendl; // find item in LRU queue and push back decode_tbls_lru->splice(decode_tbls_lru->end(), *decode_tbls_lru, (*decode_tbls_map)[signature].first); return; } // evt. shrink the LRU queue/map if ((int)decode_tbls_lru->size() >= ErasureCodeShecTableCache::decoding_tables_lru_length) { dout(20) << "[ shrink lru ] = " << signature << dendl; // remove from map decode_tbls_map->erase(decode_tbls_lru->front()); // remove from lru decode_tbls_lru->pop_front(); } { dout(20) << "[ store table ] = " << signature << dendl; decode_tbls_lru->push_back(signature); // allocate a new buffer lru_list_t::iterator it_end = decode_tbls_lru->end(); --it_end; lru_entry_t &map_value = (*decode_tbls_map)[signature] = std::make_pair(it_end, DecodingCacheParameter()); map_value.second.decoding_matrix = new int[k*k]; map_value.second.dm_row = new int[k]; map_value.second.dm_column = new int[k]; map_value.second.minimum = new int[k+m]; memcpy(map_value.second.decoding_matrix, decoding_matrix, k * k * sizeof(int)); memcpy(map_value.second.dm_row, dm_row, k * sizeof(int)); memcpy(map_value.second.dm_column, dm_column, k * sizeof(int)); memcpy(map_value.second.minimum, minimum, (k+m) * sizeof(int)); dout(20) << "[ cache size ] = " << decode_tbls_lru->size() << dendl; } }