Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Do not attempt to process a delta-manifest if its baseline-manifest is a phantom. Defer processing until the phantom is resolved. |
|---|---|
| Timelines: | family | ancestors | descendants | both | experimental |
| Files: | files | file ages | folders |
| SHA1: |
b073039b8cfecbc61819f123ce92d606 |
| User & Date: | drh 2010-10-28 01:58:30.000 |
Context
|
2010-10-28
| ||
| 03:41 | Fix the termination condition for the clone client so that it does not stop transferring before all the artifacts have been sent. check-in: 0bb7d7b8ef user: drh tags: experimental | |
| 01:58 | Do not attempt to process a delta-manifest if its baseline-manifest is a phantom. Defer processing until the phantom is resolved. check-in: b073039b8c user: drh tags: experimental | |
|
2010-10-27
| ||
| 19:17 | Do not allow clusters larger than about 900 entries. check-in: 06475b2e61 user: drh tags: experimental | |
Changes
Changes to src/content.c.
| ︙ | ︙ | |||
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
*/
static int ignoreDephantomizations = 0;
/*
** When a record is converted from a phantom to a real record,
** if that record has other records that are derived by delta,
** then call manifest_crosslink() on those other records.
**
** Tail recursion is used to minimize stack depth.
*/
void after_dephantomize(int rid, int linkFlag){
Stmt q;
int nChildAlloc = 0;
int *aChild = 0;
if( ignoreDephantomizations ) return;
while( rid ){
int nChildUsed = 0;
int i;
if( linkFlag ){
| > > > > > > > > < > > > > > > > > > > > > > > > > > > > > > > > > > > > | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
*/
static int ignoreDephantomizations = 0;
/*
** When a record is converted from a phantom to a real record,
** if that record has other records that are derived by delta,
** then call manifest_crosslink() on those other records.
**
** If the formerly phantom record or any of the other records
** derived by delta from the former phantom are a baseline manifest,
** then also invoke manifest_crosslink() on the delta-manifests
** associated with that baseline.
**
** Tail recursion is used to minimize stack depth.
*/
void after_dephantomize(int rid, int linkFlag){
Stmt q;
int nChildAlloc = 0;
int *aChild = 0;
Blob content;
if( ignoreDephantomizations ) return;
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
manifest_crosslink(rid, &content);
blob_reset(&content);
}
/* Parse all delta-manifests that depend on baseline-manifest rid */
db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
if( nChildUsed>=nChildAlloc ){
nChildAlloc = nChildAlloc*2 + 10;
aChild = fossil_realloc(aChild, nChildAlloc*sizeof(aChild));
}
aChild[nChildUsed++] = child;
}
db_finalize(&q);
for(i=0; i<nChildUsed; i++){
content_get(aChild[i], &content);
manifest_crosslink(aChild[i], &content);
blob_reset(&content);
}
if( nChildUsed ){
db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
}
/* Recursively dephantomize all artifacts that are derived by
** delta from artifact rid */
nChildUsed = 0;
db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
if( nChildUsed>=nChildAlloc ){
nChildAlloc = nChildAlloc*2 + 10;
aChild = fossil_realloc(aChild, nChildAlloc*sizeof(aChild));
}
aChild[nChildUsed++] = child;
}
db_finalize(&q);
for(i=1; i<nChildUsed; i++){
after_dephantomize(aChild[i], 1);
}
/* Tail recursion for the common case where only a single artifact
** is derived by delta from rid... */
rid = nChildUsed>0 ? aChild[0] : 0;
linkFlag = 1;
}
free(aChild);
}
/*
|
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
911 912 913 914 915 916 917 |
p = manifest_parse(&b2, 0);
manifest_destroy(p);
}
}
/*
** Fetch the baseline associated with the delta-manifest p.
| | > > > | > > > > > > > > > > > > > > > > | | 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 |
p = manifest_parse(&b2, 0);
manifest_destroy(p);
}
}
/*
** Fetch the baseline associated with the delta-manifest p.
** Return 0 on success. If unable to parse the baseline,
** throw an error. If the baseline is a manifest, throw an
** error if throwError is true, or record that p is an orphan
** and return 1 throwError is false.
*/
static int fetch_baseline(Manifest *p, int throwError){
if( p->zBaseline!=0 && p->pBaseline==0 ){
int rid = uuid_to_rid(p->zBaseline, 0);
if( rid==0 && !throwError ){
rid = content_new(p->zBaseline);
db_multi_exec(
"INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
rid, p->rid
);
return 1;
}
p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST);
if( p->pBaseline==0 ){
if( !throwError && db_exists("SELECT 1 FROM phantom WHERE rid=%d",rid) ){
db_multi_exec(
"INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
rid, p->rid
);
return 1;
}
fossil_fatal("cannot access baseline manifest %S", p->zBaseline);
}
}
return 0;
}
/*
** Rewind a manifest-file iterator back to the beginning of the manifest.
*/
void manifest_file_rewind(Manifest *p){
p->iFile = 0;
fetch_baseline(p, 1);
if( p->pBaseline ){
p->pBaseline->iFile = 0;
}
}
/*
** Advance to the next manifest-file.
|
| ︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 |
*/
ManifestFile *manifest_file_seek(Manifest *p, const char *zName){
ManifestFile *pFile;
pFile = manifest_file_seek_base(p, zName);
if( pFile && pFile->zUuid==0 ) return 0;
if( pFile==0 && p->zBaseline ){
| | | 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 |
*/
ManifestFile *manifest_file_seek(Manifest *p, const char *zName){
ManifestFile *pFile;
pFile = manifest_file_seek_base(p, zName);
if( pFile && pFile->zUuid==0 ) return 0;
if( pFile==0 && p->zBaseline ){
fetch_baseline(p, 1);
pFile = manifest_file_seek_base(p->pBaseline, zName);
}
return pFile;
}
/*
** This strcmp() function handles NULL arguments. NULLs sort first.
|
| ︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
otherRid = cid;
}
if( (*ppOther = manifest_cache_find(otherRid))==0 ){
content_get(otherRid, &otherContent);
if( blob_size(&otherContent)==0 ) return;
*ppOther = manifest_parse(&otherContent, otherRid);
if( *ppOther==0 ) return;
}
if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
content_deltify(pid, cid, 0);
}else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
| > > > > < | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
otherRid = cid;
}
if( (*ppOther = manifest_cache_find(otherRid))==0 ){
content_get(otherRid, &otherContent);
if( blob_size(&otherContent)==0 ) return;
*ppOther = manifest_parse(&otherContent, otherRid);
if( *ppOther==0 ) return;
}
if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
manifest_destroy(*ppOther);
return;
}
if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
content_deltify(pid, cid, 0);
}else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
content_deltify(pParent->pBaseline->rid, cid, 0);
}
for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
if( pChildFile->zPrior ){
pParentFile = manifest_file_seek(pParent, pChildFile->zPrior);
if( pParentFile ){
|
| ︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 |
blob_reset(pContent);
}else if( (p = manifest_parse(pContent, rid))==0 ){
return 0;
}
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
manifest_destroy(p);
return 0;
}
db_begin_transaction();
if( p->type==CFTYPE_MANIFEST ){
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
char *zCom;
for(i=0; i<p->nParent; i++){
int pid = uuid_to_rid(p->azParent[i], 1);
| > > > > | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
blob_reset(pContent);
}else if( (p = manifest_parse(pContent, rid))==0 ){
return 0;
}
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
manifest_destroy(p);
return 0;
}
if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
manifest_destroy(p);
return 0;
}
db_begin_transaction();
if( p->type==CFTYPE_MANIFEST ){
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
char *zCom;
for(i=0; i<p->nParent; i++){
int pid = uuid_to_rid(p->azParent[i], 1);
|
| ︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 |
db_set_int("seen-delta-manifest", 1, 0);
once = 0;
}
}
}
}
if( p->type==CFTYPE_CLUSTER ){
tag_insert("cluster", 1, 0, rid, p->rDate, rid);
for(i=0; i<p->nCChild; i++){
int mid;
mid = uuid_to_rid(p->azCChild[i], 1);
if( mid>0 ){
| > > | > > | 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 |
db_set_int("seen-delta-manifest", 1, 0);
once = 0;
}
}
}
}
if( p->type==CFTYPE_CLUSTER ){
static Stmt del1;
tag_insert("cluster", 1, 0, rid, p->rDate, rid);
db_static_prepare(&del1, "DELETE FROM unclustered WHERE rid=:rid");
for(i=0; i<p->nCChild; i++){
int mid;
mid = uuid_to_rid(p->azCChild[i], 1);
if( mid>0 ){
db_bind_int(&del1, ":rid", mid);
db_step(&del1);
db_reset(&del1);
}
}
}
if( p->type==CFTYPE_CONTROL
|| p->type==CFTYPE_MANIFEST
|| p->type==CFTYPE_EVENT
){
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 | @ @ -- A record of phantoms. A phantom is a record for which we know the @ -- UUID but we do not (yet) know the file content. @ -- @ CREATE TABLE phantom( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- Unclustered records. An unclustered record is a record (including @ -- a cluster records themselves) that is not mentioned by some other @ -- cluster. @ -- @ -- Phantoms are usually included in the unclustered table. A new cluster @ -- will never be created that contains a phantom. But another repository | > > > > > > > > > > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | @ @ -- A record of phantoms. A phantom is a record for which we know the @ -- UUID but we do not (yet) know the file content. @ -- @ CREATE TABLE phantom( @ rid INTEGER PRIMARY KEY -- Record ID of the phantom @ ); @ @ -- A record of orphaned delta-manifests. An orphan is a delta-manifest @ -- for which we have content, but its baseline-manifest is a phantom. @ -- We have to track all orphan maniftests so that when the baseline arrives, @ -- we know to process the orphaned deltas. @ CREATE TABLE orphan( @ rid INTEGER PRIMARY KEY, -- Delta manifest with a phantom baseline @ baseline INTEGER -- Phantom baseline of this orphan @ ); @ CREATE INDEX orphan_baseline ON orphan(baseline); @ @ -- Unclustered records. An unclustered record is a record (including @ -- a cluster records themselves) that is not mentioned by some other @ -- cluster. @ -- @ -- Phantoms are usually included in the unclustered table. A new cluster @ -- will never be created that contains a phantom. But another repository |
| ︙ | ︙ |