/* -------------------------------------------------------------------------- */ /* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); you may */ /* not use this file except in compliance with the License. You may obtain */ /* a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ /* See the License for the specific language governing permissions and */ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ #ifndef BITMAP_H_ #define BITMAP_H_ #include #include "Attribute.h" #include "Callbackable.h" class SqlDB; /** * This class represents a generic BitMap * */ template class BitMap : public Callbackable { public: /** * Creates a new bitmap, it stores a pointer to the DB parameters * that MUST exists during the object lifetime. */ BitMap(const VectorAttribute& bs_conf, int _id, const char * _db_table) : id(_id), start_bit(0), bs(0), db_table(_db_table) { std::string reserved; bs_conf.vector_value("START", start_bit); bs_conf.vector_value("RESERVED", reserved); if (!reserved.empty()) { set_reserved_bit(reserved); } }; virtual ~BitMap() { delete bs; }; /* ---------------------------------------------------------------------- */ /* Database interface */ /* ---------------------------------------------------------------------- */ /** * Returns a string stream with the SQL bootstrap command for the * bitmap table */ static std::ostringstream& bootstrap(const char * t, std::ostringstream& o) { o << "CREATE TABLE IF NOT EXISTS " << t << " (id INTEGER, map LONGTEXT, PRIMARY KEY(id))"; return o; } /** * Insert a new zero'ed bitmap into the bitmap table. This function is * called once to bootstrap the bitmap contents. * @param id of the set, this will update the id of the bitmap * @return 0 on success */ int insert(int _id, SqlDB * db) { id = _id; bs = new std::bitset; return insert_replace(db, false); } /** * Loads a bitmap from its string representation. This function is called * once to load the bitmap from the DB. * @param id of the set, this will update the id of the bitmap * @return 0 on success */ int select(int _id, SqlDB * db) { std::string * uzbs; id = _id; if ( select(db, &uzbs) != 0 ) { return -1; } bs = new std::bitset(*uzbs); delete uzbs; return 0; } int update(SqlDB * db) { return insert_replace(db, true); } /** * Deletes a bitmap from the DB. * @return 0 on success */ int drop(SqlDB * db) { std::ostringstream oss; oss << "DELETE FROM " << db_table << " WHERE id = " << id ; return db->exec_wr(oss); } /* ---------------------------------------------------------------------- */ /* BitMap interface */ /* ---------------------------------------------------------------------- */ /*+ * Gets the first 0 bit in the map (and not reserved) and set it. * @param hint try this bit first, 0 does not use any hint * @param bit the bit number reserved * @return -1 in case of error */ int get(unsigned int hint, unsigned int& bit) { if ( hint != 0 ) { if ( bs->test(hint) == false && reserved_bit.count(hint) == 0 ) { bs->set(hint); bit = hint; return 0; } } for (bit = start_bit; ; ++bit) { try { if ( bs->test(bit) == false && reserved_bit.count(bit) == 0) { bs->set(bit); return 0; } } catch (const std::out_of_range& oor) { return -1; } } return -1; } /** * Clears a bit in the map and updates DB. * @param bit to reset */ void reset(int bit) { try { bs->reset(bit); } catch(const std::out_of_range& oor){}; } /** * Sets a bit in the map and updates DB. * @param bit to set * @return 0 on success, -1 if bit was set */ int set(int bit) { int rc = -1; try { if (bs->test(bit) == false) { bs->set(bit); rc = 0; } } catch(const std::out_of_range& oor){}; return rc; } /** * Return the start_bit of the bitmap */ unsigned int get_start_bit() { return start_bit; } private: /* ---------------------------------------------------------------------- */ /* Bitmap configuration attributes */ /* ---------------------------------------------------------------------- */ int id; unsigned int start_bit; std::set reserved_bit; std::bitset * bs; /* ---------------------------------------------------------------------- */ /* Database implementation */ /* ---------------------------------------------------------------------- */ const char * db_table; /** * Select callback from DB engine */ int select_cb(void * _bs, int num, char **values, char **names) { if ( num == 0 || values == 0 || values[0] == 0 ) { return -1; } *static_cast(_bs) = (const char *) values[0]; return 0; } /** * Loads a the contents of a bitmap from DB * @param **uzbs, pointer to a string pointer to store the bitmap, must * be freed by caller. * @return 0 on success */ int select(SqlDB * db, std::string ** uzbs) { int rc; std::ostringstream oss; std::string zbs; *uzbs = 0; set_callback(static_cast(&BitMap::select_cb), static_cast(&zbs)); oss << "SELECT map FROM " << db_table << " WHERE id = " << id ; rc = db->exec_rd(oss, this); unset_callback(); if ( rc != 0 ) { return rc; } else if (zbs.empty()) { return -1; } *uzbs = one_util::zlib_decompress(zbs, true); if ( *uzbs == 0 ) { rc = -1; } return rc; } /** * Insert a Bitmap in the DB, the bitmap is stored in a compressed (zlib) * string form. * @param replace true to replace false to insert * @return 0 on success */ int insert_replace(SqlDB * db, bool replace) { std::ostringstream oss; std::string * zipped = one_util::zlib_compress(bs->to_string(), true); if (zipped == 0) { return -1; } char * ezipped64 = db->escape_str(*zipped); if (replace) { oss << "UPDATE " << db_table << " SET " << "map = '" << ezipped64 << "' " << "WHERE id = " << id; } else { oss << "INSERT INTO " << db_table << " (id, map) VALUES (" << id << ",'" << ezipped64 << "')"; } int rc = db->exec_wr(oss); delete zipped; db->free_str(ezipped64); return rc; } /** * The reserved bit string is separated by ',' for each element * and by ':' for ranges. * @param string with reserved bits */ void set_reserved_bit(std::string& reserved) { std::vector strings; std::vector range; std::vector::const_iterator it; std::istringstream iss; unsigned int bit, bit_start, bit_end; strings = one_util::split(reserved, ',', true); for (it = strings.begin(); it != strings.end(); it++) { // Try to split it by ':' range = one_util::split(*it, ':', true); iss.clear(); iss.str(range[0]); iss >> bit_start; if ( iss.fail() ) { continue; } if (range.size() == 1) { bit_end = bit_start; } else if (range.size() == 2) { iss.clear(); iss.str(range[1]); iss >> bit_end; if ( iss.fail() ) { continue; } } else { continue; } for (bit = bit_start; bit <= bit_end; bit++) { reserved_bit.insert(bit); } } } }; #endif /*BITMAP_H_*/