2016-04-05 13:47:21 +03:00
/* -------------------------------------------------------------------------- */
2020-04-30 16:00:02 +03:00
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
2016-04-05 13:47:21 +03:00
/* */
/* 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 <bitset>
# include "Attribute.h"
# include "Callbackable.h"
class SqlDB ;
/**
* This class represents a generic BitMap
*
*/
template < unsigned int N >
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 ( ) )
{
2016-08-30 13:20:07 +03:00
set_reserved_bit ( reserved ) ;
2016-04-05 13:47:21 +03:00
}
} ;
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 ;
}
/**
2016-05-10 20:41:12 +03:00
* Insert a new zero ' ed bitmap into the bitmap table . This function is
* called once to bootstrap the bitmap contents .
2016-04-05 13:47:21 +03:00
* @ 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 ;
2016-05-10 20:41:12 +03:00
bs = new std : : bitset < N > ;
2016-04-05 13:47:21 +03:00
return insert_replace ( db , false ) ;
}
/**
2016-05-10 20:41:12 +03:00
* Loads a bitmap from its string representation . This function is called
* once to load the bitmap from the DB .
2016-04-05 13:47:21 +03:00
* @ 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 ;
}
2016-05-10 20:41:12 +03:00
bs = new std : : bitset < N > ( * uzbs ) ;
2016-04-05 13:47:21 +03:00
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 ;
2017-04-18 17:32:23 +03:00
return db - > exec_wr ( oss ) ;
2016-04-05 13:47:21 +03:00
}
/* ---------------------------------------------------------------------- */
/* BitMap interface */
/* ---------------------------------------------------------------------- */
/*+
2016-05-10 20:41:12 +03:00
* Gets the first 0 bit in the map ( and not reserved ) and set it .
2016-04-05 13:47:21 +03:00
* @ 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 )
{
2016-05-10 20:41:12 +03:00
if ( bs - > test ( hint ) = = false & & reserved_bit . count ( hint ) = = 0 )
2016-04-05 13:47:21 +03:00
{
bs - > set ( hint ) ;
bit = hint ;
return 0 ;
}
}
for ( bit = start_bit ; ; + + bit )
{
try
{
2016-05-10 20:41:12 +03:00
if ( bs - > test ( bit ) = = false & & reserved_bit . count ( bit ) = = 0 )
2016-04-05 13:47:21 +03:00
{
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 ;
2016-05-10 20:41:12 +03:00
std : : set < unsigned int > reserved_bit ;
2016-04-05 13:47:21 +03:00
std : : bitset < N > * 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 < std : : string * > ( _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 < Callbackable : : Callback > ( & BitMap : : select_cb ) ,
static_cast < void * > ( & zbs ) ) ;
oss < < " SELECT map FROM " < < db_table < < " WHERE id = " < < id ;
2017-04-18 17:32:23 +03:00
rc = db - > exec_rd ( oss , this ) ;
2016-04-05 13:47:21 +03:00
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 ;
}
2019-09-03 17:31:51 +03:00
char * ezipped64 = db - > escape_str ( * zipped ) ;
2016-04-05 13:47:21 +03:00
2019-06-12 18:20:50 +03:00
if ( replace )
{
oss < < " UPDATE " < < db_table < < " SET "
< < " map = ' " < < ezipped64 < < " ' "
< < " WHERE id = " < < id ;
}
else
{
oss < < " INSERT INTO " < < db_table < < " (id, map) VALUES ( "
2016-04-05 13:47:21 +03:00
< < id < < " ,' " < < ezipped64 < < " ') " ;
2019-06-12 18:20:50 +03:00
}
2016-04-05 13:47:21 +03:00
2017-04-18 17:32:23 +03:00
int rc = db - > exec_wr ( oss ) ;
2016-04-05 13:47:21 +03:00
delete zipped ;
db - > free_str ( ezipped64 ) ;
return rc ;
}
2016-08-30 13:20:07 +03:00
/**
* 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 < std : : string > strings ;
std : : vector < std : : string > range ;
std : : vector < std : : string > : : 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 ) ;
}
}
}
2016-04-05 13:47:21 +03:00
} ;
# endif /*BITMAP_H_*/