2015-09-29 19:19:54 +00:00
# include <common/JSON.h>
2015-09-29 14:09:01 +00:00
# include <Poco/Path.h>
2017-04-01 09:19:00 +00:00
# include <IO/WriteBufferFromFile.h>
# include <IO/ReadBufferFromFile.h>
# include <IO/WriteBufferFromString.h>
# include <IO/WriteHelpers.h>
# include <IO/ReadHelpers.h>
# include <Common/escapeForFileName.h>
# include <Common/FileChecker.h>
2015-09-29 14:09:01 +00:00
namespace DB
{
2017-02-06 12:09:54 +00:00
FileChecker : : FileChecker ( const std : : string & file_info_path_ )
2015-09-29 14:09:01 +00:00
{
2017-04-01 07:20:54 +00:00
setPath ( file_info_path_ ) ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : setPath ( const std : : string & file_info_path_ )
{
2017-04-01 07:20:54 +00:00
files_info_path = file_info_path_ ;
2017-02-06 12:09:54 +00:00
2017-04-01 07:20:54 +00:00
Poco : : Path path ( files_info_path ) ;
tmp_files_info_path = path . parent ( ) . toString ( ) + " tmp_ " + path . getFileName ( ) ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : update ( const Poco : : File & file )
{
2017-04-01 07:20:54 +00:00
initialize ( ) ;
updateImpl ( file ) ;
save ( ) ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : update ( const Files : : const_iterator & begin , const Files : : const_iterator & end )
{
2017-04-01 07:20:54 +00:00
initialize ( ) ;
for ( auto it = begin ; it ! = end ; + + it )
updateImpl ( * it ) ;
save ( ) ;
2015-09-29 14:09:01 +00:00
}
2019-07-03 13:17:19 +00:00
CheckResults FileChecker : : check ( ) const
2015-09-29 14:09:01 +00:00
{
2017-04-01 07:20:54 +00:00
/** Read the files again every time you call `check` - so as not to violate the constancy.
* ` check ` method is rarely called .
*/
2019-07-03 13:17:19 +00:00
CheckResults results ;
2017-04-01 07:20:54 +00:00
Map local_map ;
2018-08-26 02:08:35 +00:00
load ( local_map , files_info_path ) ;
2017-04-01 07:20:54 +00:00
if ( local_map . empty ( ) )
2019-07-03 13:17:19 +00:00
return { } ;
2017-04-01 07:20:54 +00:00
for ( const auto & name_size : local_map )
{
2019-07-03 16:00:24 +00:00
Poco : : Path path = Poco : : Path ( files_info_path ) . parent ( ) . toString ( ) + " / " + name_size . first ;
Poco : : File file ( path ) ;
2017-04-01 07:20:54 +00:00
if ( ! file . exists ( ) )
{
2019-07-03 16:00:24 +00:00
results . emplace_back ( path . getFileName ( ) , false , " File " + file . path ( ) + " doesn't exist " ) ;
2019-07-03 13:17:19 +00:00
break ;
2017-04-01 07:20:54 +00:00
}
2019-07-03 13:17:19 +00:00
2017-04-01 07:20:54 +00:00
size_t real_size = file . getSize ( ) ;
if ( real_size ! = name_size . second )
{
2019-07-03 16:00:24 +00:00
results . emplace_back ( path . getFileName ( ) , false , " Size of " + file . path ( ) + " is wrong. Size is " + toString ( real_size ) + " but should be " + toString ( name_size . second ) ) ;
2019-07-03 13:17:19 +00:00
break ;
2017-04-01 07:20:54 +00:00
}
2019-07-03 16:00:24 +00:00
results . emplace_back ( path . getFileName ( ) , true , " " ) ;
2017-04-01 07:20:54 +00:00
}
2019-07-03 13:17:19 +00:00
return results ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : initialize ( )
{
2017-04-01 07:20:54 +00:00
if ( initialized )
return ;
2015-09-29 14:09:01 +00:00
2018-08-26 02:08:35 +00:00
load ( map , files_info_path ) ;
2017-04-01 07:20:54 +00:00
initialized = true ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : updateImpl ( const Poco : : File & file )
{
2017-04-01 07:20:54 +00:00
map [ Poco : : Path ( file . path ( ) ) . getFileName ( ) ] = file . getSize ( ) ;
2015-09-29 14:09:01 +00:00
}
void FileChecker : : save ( ) const
{
2017-04-01 07:20:54 +00:00
{
WriteBufferFromFile out ( tmp_files_info_path ) ;
/// So complex JSON structure - for compatibility with the old format.
writeCString ( " { \" yandex \" :{ " , out ) ;
2018-08-07 17:04:39 +00:00
auto settings = FormatSettings ( ) ;
2017-04-01 07:20:54 +00:00
for ( auto it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it ! = map . begin ( ) )
writeString ( " , " , out ) ;
/// `escapeForFileName` is not really needed. But it is left for compatibility with the old code.
2018-08-07 17:04:39 +00:00
writeJSONString ( escapeForFileName ( it - > first ) , out , settings ) ;
2017-04-01 07:20:54 +00:00
writeString ( " :{ \" size \" : \" " , out ) ;
writeIntText ( it - > second , out ) ;
writeString ( " \" } " , out ) ;
}
writeCString ( " }} " , out ) ;
out . next ( ) ;
}
Poco : : File current_file ( files_info_path ) ;
if ( current_file . exists ( ) )
{
std : : string old_file_name = files_info_path + " .old " ;
current_file . renameTo ( old_file_name ) ;
Poco : : File ( tmp_files_info_path ) . renameTo ( files_info_path ) ;
Poco : : File ( old_file_name ) . remove ( ) ;
}
else
Poco : : File ( tmp_files_info_path ) . renameTo ( files_info_path ) ;
2015-09-29 14:09:01 +00:00
}
2018-08-26 02:08:35 +00:00
void FileChecker : : load ( Map & local_map , const std : : string & path )
2015-09-29 14:09:01 +00:00
{
2018-08-26 02:08:35 +00:00
local_map . clear ( ) ;
2017-04-01 07:20:54 +00:00
2018-08-26 02:08:35 +00:00
if ( ! Poco : : File ( path ) . exists ( ) )
2017-04-01 07:20:54 +00:00
return ;
2018-08-26 02:08:35 +00:00
ReadBufferFromFile in ( path ) ;
2017-07-31 21:39:24 +00:00
WriteBufferFromOwnString out ;
2017-04-01 07:20:54 +00:00
2017-07-31 21:39:24 +00:00
/// The JSON library does not support whitespace. We delete them. Inefficient.
while ( ! in . eof ( ) )
{
char c ;
readChar ( c , in ) ;
if ( ! isspace ( c ) )
writeChar ( c , out ) ;
2017-04-01 07:20:54 +00:00
}
2017-07-31 21:39:24 +00:00
JSON json ( out . str ( ) ) ;
2017-04-01 07:20:54 +00:00
JSON files = json [ " yandex " ] ;
2019-01-04 12:10:00 +00:00
for ( const JSON name_value : files )
2018-08-26 02:08:35 +00:00
local_map [ unescapeForFileName ( name_value . getName ( ) ) ] = name_value . getValue ( ) [ " size " ] . toUInt ( ) ;
2015-09-29 14:09:01 +00:00
}
}