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