Artifact 4c09bcd36f1ffd535834f886454723abd3716936
File
src/verify.c
part of check-in
[0afb5e8e39]
- This version is able to clone the entire TCL repository in 12.5 minutes
and to rebuild the cloned TCL repository in 2.5 minutes. There is still
a lot of performance work to be done, but this is good enough for the
time being.
by
drh on
2008-03-08 14:52:56.
/*
** Copyright (c) 2007 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License version 2 as published by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to help verify the integrity of the
** the repository.
**
** This file primarily implements the verify_before_commit() interface.
** Any function can call verify_before_commit() with a record id (RID)
** as an argument. Then before the next change to the database commits,
** this routine will reach in and check that the record can be extracted
** correctly from the BLOB table.
*/
#include "config.h"
#include "verify.h"
#include <assert.h>
/*
** Load the record identify by rid. Make sure we can reproduce it
** without error.
**
** Panic if anything goes wrong. If this procedure returns it means
** that everything is OK.
*/
static void verify_rid(int rid){
Blob uuid, hash, content;
if( db_int(0, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){
return; /* No way to verify phantoms */
}
blob_zero(&uuid);
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
if( blob_size(&uuid)!=UUID_SIZE ){
fossil_panic("not a valid rid: %d", rid);
}
if( content_get(rid, &content) ){
sha1sum_blob(&content, &hash);
blob_reset(&content);
if( blob_compare(&uuid, &hash) ){
fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
rid, &hash, &uuid);
}
blob_reset(&hash);
}
blob_reset(&uuid);
}
/*
** The following bag holds the rid for every record that needs
** to be verified.
*/
static Bag toVerify;
static int inFinalVerify = 0;
/*
** This routine is called just prior to each commit operation.
*/
static int verify_at_commit(void){
int rid;
content_clear_cache();
inFinalVerify = 1;
rid = bag_first(&toVerify);
while( rid>0 ){
verify_rid(rid);
rid = bag_next(&toVerify, rid);
}
bag_clear(&toVerify);
inFinalVerify = 0;
return 0;
}
/*
** Arrange to verify a particular record prior to committing.
**
** If the record rid is less than 1, then just initialize the
** verification system but do not record anything as needing
** verification.
*/
void verify_before_commit(int rid){
static int isInit = 0;
if( !isInit ){
db_commit_hook(verify_at_commit, 1000);
isInit = 1;
}
assert( !inFinalVerify );
if( rid>0 ){
bag_insert(&toVerify, rid);
}
}
/*
** Cancel all pending verification operations.
*/
void verify_cancel(void){
bag_clear(&toVerify);
}
/*
** COMMAND: test-verify-all
**
** Verify all records in the repository.
*/
void verify_all_cmd(void){
Stmt q;
int cnt = 0;
db_must_be_within_tree();
db_prepare(&q, "SELECT rid FROM blob");
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
verify_before_commit(rid);
cnt++;
assert( bag_count(&toVerify)==cnt );
}
db_finalize(&q);
verify_at_commit();
assert( bag_count(&toVerify)==0 );
}