Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch mlink-improvements Through [a241444d8f] Excluding Merge-Ins
This is equivalent to a diff from ae3ef4d3d9 to a241444d8f
|
2015-01-25
| ||
| 21:21 | Improved tracing capability for debugging purposes. ... (check-in: af3d3b6936 user: drh tags: trunk) | |
| 09:54 | Merge latest trunk ... (check-in: befd44c747 user: baruch tags: svn-import) | |
| 01:30 | Comment improvements in the schema. Attempt to get the /finfo page to show merge arrows. ... (check-in: 7d5a85bba8 user: drh tags: mlink-improvements) | |
| 00:20 | Enhance the MLINK table schema to record file changes from all parents. Requires a "fossil rebuild". Other schema cleanups at the same time. ... (check-in: a241444d8f user: drh tags: mlink-improvements) | |
|
2015-01-24
| ||
| 22:13 | Enhance the "fossil sync" command to retry all of the returned values from getaddrinfo() until it finds one that actually works. That way, it will find the IPv4 version on machines that do not have an IPv6 gateway. ... (check-in: ae3ef4d3d9 user: drh tags: trunk) | |
| 21:46 | Add the --ipv4 option to force the use of IPv4 on "fossil clone" and "fossil sync" and so forth. ... (check-in: 317bd3cb3d user: drh tags: trunk) | |
Changes to src/browse.c.
| ︙ | ︙ | |||
905 906 907 908 909 910 911 912 913 914 915 916 917 918 | @ WITH RECURSIVE @ ckin(x) AS (VALUES(:ckin) UNION ALL @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim) @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname) @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name @ FROM ckin, mlink, event, filename @ WHERE mlink.mid=ckin.x @ AND mlink.fnid IN (SELECT fnid FROM foci, filename @ WHERE foci.checkinID=:ckin @ AND filename.name=foci.filename @ AND filename.name GLOB :glob) @ AND filename.fnid=mlink.fnid @ AND event.objid=mlink.mid; ; | > | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 | @ WITH RECURSIVE @ ckin(x) AS (VALUES(:ckin) UNION ALL @ SELECT pid FROM ckin, plink WHERE cid=x AND isprim) @ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname) @ SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name @ FROM ckin, mlink, event, filename @ WHERE mlink.mid=ckin.x @ AND NOT mlink.isaux @ AND mlink.fnid IN (SELECT fnid FROM foci, filename @ WHERE foci.checkinID=:ckin @ AND filename.name=foci.filename @ AND filename.name GLOB :glob) @ AND filename.fnid=mlink.fnid @ AND event.objid=mlink.mid; ; |
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 | } /* ** Add a single entry to the mlink table. Also add the filename to ** the filename table if it is not there already. */ static void add_one_mlink( | | | > | > | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 |
}
/*
** Add a single entry to the mlink table. Also add the filename to
** the filename table if it is not there already.
*/
static void add_one_mlink(
int pmid, /* The parent manifest */
const char *zFromUuid, /* UUID for content in parent */
int mid, /* The record ID of the manifest */
const char *zToUuid, /* UUID for content in child */
const char *zFilename, /* Filename */
const char *zPrior, /* Previous filename. NULL if unchanged */
int isPublic, /* True if mid is not a private manifest */
int isPrimary, /* pmid is the primary parent of mid */
int mperm /* 1: exec, 2: symlink */
){
int fnid, pfnid, pid, fid;
static Stmt s1;
fnid = filename_to_fnid(zFilename);
if( zPrior==0 ){
|
| ︙ | ︙ | |||
1214 1215 1216 1217 1218 1219 1220 |
if( zToUuid==0 || zToUuid[0]==0 ){
fid = 0;
}else{
fid = uuid_to_rid(zToUuid, 1);
if( isPublic ) content_make_public(fid);
}
db_static_prepare(&s1,
| | | | | > > | 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 |
if( zToUuid==0 || zToUuid[0]==0 ){
fid = 0;
}else{
fid = uuid_to_rid(zToUuid, 1);
if( isPublic ) content_make_public(fid);
}
db_static_prepare(&s1,
"INSERT INTO mlink(mid,fid,pmid,pid,fnid,pfnid,mperm,isaux)"
"VALUES(:m,:f,:pm,:p,:n,:pfn,:mp,:isaux)"
);
db_bind_int(&s1, ":m", mid);
db_bind_int(&s1, ":f", fid);
db_bind_int(&s1, ":pm", pmid);
db_bind_int(&s1, ":p", pid);
db_bind_int(&s1, ":n", fnid);
db_bind_int(&s1, ":pfn", pfnid);
db_bind_int(&s1, ":mp", mperm);
db_bind_int(&s1, ":isaux", isPrimary==0);
db_exec(&s1);
if( pid && fid ){
content_deltify(pid, fid, 0);
}
}
/*
|
| ︙ | ︙ | |||
1340 1341 1342 1343 1344 1345 1346 | ** A single mlink entry is added for every file that changed content, ** name, and/or permissions going from pid to cid. ** ** Deleted files have mlink.fid=0. ** Added files have mlink.pid=0. ** Edited files have both mlink.pid!=0 and mlink.fid!=0 */ | | > > > > | | | | > | | | | | | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 |
** A single mlink entry is added for every file that changed content,
** name, and/or permissions going from pid to cid.
**
** Deleted files have mlink.fid=0.
** Added files have mlink.pid=0.
** Edited files have both mlink.pid!=0 and mlink.fid!=0
*/
static void add_mlink(
int pmid, Manifest *pParent, /* Parent check-in */
int mid, Manifest *pChild, /* The child check-in */
int isPrim /* TRUE if pmid is the primary parent of mid */
){
Blob otherContent;
int otherRid;
int i, rc;
ManifestFile *pChildFile, *pParentFile;
Manifest **ppOther;
static Stmt eq;
int isPublic; /* True if pChild is non-private */
/* If mlink table entires are already exist for the pmid-to-mid transition,
** then abort early doing no work.
*/
db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid AND pmid=:pmid");
db_bind_int(&eq, ":mid", mid);
db_bind_int(&eq, ":pmid", pmid);
rc = db_step(&eq);
db_reset(&eq);
if( rc==SQLITE_ROW ) return;
/* Compute the value of the missing pParent or pChild parameter.
** Fetch the baseline checkins for both.
*/
assert( pParent==0 || pChild==0 );
if( pParent==0 ){
ppOther = &pParent;
otherRid = pmid;
}else{
ppOther = &pChild;
otherRid = mid;
}
if( (*ppOther = manifest_cache_find(otherRid))==0 ){
content_get(otherRid, &otherContent);
if( blob_size(&otherContent)==0 ) return;
*ppOther = manifest_parse(&otherContent, otherRid, 0);
if( *ppOther==0 ) return;
}
if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
manifest_destroy(*ppOther);
return;
}
isPublic = !content_is_private(mid);
/* Try to make the parent manifest a delta from the child, if that
** is an appropriate thing to do. For a new baseline, make the
** previous baseline a delta from the current baseline.
*/
if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
content_deltify(pmid, mid, 0);
}else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
content_deltify(pParent->pBaseline->rid, mid, 0);
}
/* Remember all children less than a few seconds younger than their parent,
** as we might want to fudge the times for those children.
*/
if( pChild->rDate<pParent->rDate+AGE_FUDGE_WINDOW
&& manifest_crosslink_busy
|
| ︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 |
*/
for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
int mperm = manifest_file_mperm(pChildFile);
if( pChildFile->zPrior ){
pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
if( pParentFile ){
/* File with name change */
| | | > | | | | | | | | | | | | | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
*/
for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
int mperm = manifest_file_mperm(pChildFile);
if( pChildFile->zPrior ){
pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
if( pParentFile ){
/* File with name change */
add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
pChildFile->zName, pChildFile->zPrior,
isPublic, isPrim, mperm);
}else{
/* File name changed, but the old name is not found in the parent!
** Treat this like a new file. */
add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
isPublic, isPrim, mperm);
}
}else{
pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
if( pParentFile==0 ){
if( pChildFile->zUuid ){
/* A new file */
add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
isPublic, isPrim, mperm);
}
}else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
|| manifest_file_mperm(pParentFile)!=mperm ){
/* Changes in file content or permissions */
add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
pChildFile->zName, 0, isPublic, isPrim, mperm);
}
}
}
if( pParent->zBaseline && pChild->zBaseline ){
/* Both parent and child are delta manifests. Look for files that
** are deleted or modified in the parent but which reappear or revert
** to baseline in the child and show such files as being added or changed
** in the child. */
for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
if( pParentFile->zUuid ){
pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
if( pChildFile==0 ){
/* The child file reverts to baseline. Show this as a change */
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
if( pChildFile ){
add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
pChildFile->zName, 0, isPublic, isPrim,
manifest_file_mperm(pChildFile));
}
}
}else{
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
if( pChildFile ){
/* File resurrected in the child after having been deleted in
** the parent. Show this as an added file. */
add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
isPublic, isPrim, manifest_file_mperm(pChildFile));
}
}
}
}else if( pChild->zBaseline==0 ){
/* pChild is a baseline. Look for files that are present in pParent
** but are missing from pChild and mark them as having been deleted. */
manifest_file_rewind(pParent);
while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
if( pChildFile==0 && pParentFile->zUuid!=0 ){
add_one_mlink(pmid, pParentFile->zUuid, mid, 0, pParentFile->zName, 0,
isPublic, isPrim, 0);
}
}
}
manifest_cache_insert(*ppOther);
}
/*
|
| ︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 |
char zBaseId[30];
if( p->zBaseline ){
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
uuid_to_rid(p->zBaseline,1));
}else{
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
}
| < < < | | | | < < < < < < < < < | | | < | > | | | | 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 |
char zBaseId[30];
if( p->zBaseline ){
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
uuid_to_rid(p->zBaseline,1));
}else{
sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
}
for(i=0; i<p->nParent; i++){
int pid = uuid_to_rid(p->azParent[i], 1);
db_multi_exec(
"INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
"VALUES(%d, %d, %d, %.17g, %s)",
pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
add_mlink(pid, 0, rid, p, i);
if( i==0 ) parentid = pid;
}
db_prepare(&q, "SELECT cid, isprim FROM plink WHERE pid=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int cid = db_column_int(&q, 0);
int isprim = db_column_int(&q, 1);
add_mlink(rid, p, cid, 0, isprim);
}
db_finalize(&q);
if( p->nParent==0 ){
/* For root files (files without parents) add mlink entries
** showing all content as new. */
int isPublic = !content_is_private(rid);
for(i=0; i<p->nFile; i++){
add_one_mlink(0, 0, rid, p->aFile[i].zUuid, p->aFile[i].zName, 0,
isPublic, 1, manifest_file_mperm(&p->aFile[i]));
}
}
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment,"
"bgcolor,euser,ecomment,omtime)"
"VALUES('ci',"
" coalesce("
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 | ** The content tables have a content version number which rarely ** changes. The aux tables have an arbitrary version number (typically ** a date) which can change frequently. When the content schema changes, ** we have to execute special procedures to update the schema. When ** the aux schema changes, all we need to do is rebuild the database. */ #define CONTENT_SCHEMA "2" | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | ** The content tables have a content version number which rarely ** changes. The aux tables have an arbitrary version number (typically ** a date) which can change frequently. When the content schema changes, ** we have to execute special procedures to update the schema. When ** the aux schema changes, all we need to do is rebuild the database. */ #define CONTENT_SCHEMA "2" #define AUX_SCHEMA_MIN "2015-01-24" #define AUX_SCHEMA_MAX "2015-01-24" #endif /* INTERFACE */ /* ** The schema for a repository database. ** |
| ︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 | @ -- Filenames @ -- @ CREATE TABLE filename( @ fnid INTEGER PRIMARY KEY, -- Filename ID @ name TEXT UNIQUE -- Name of file page @ ); @ @ -- Linkages between checkins, files created by each checkin, and @ -- the names of those files. @ -- @ -- pid==0 if the file is added by checkin mid. @ -- fid==0 if the file is removed by checkin mid. @ -- @ CREATE TABLE mlink( | > > > > > > > > > > > > > > > > > > > > | > | < | > > | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | @ -- Filenames @ -- @ CREATE TABLE filename( @ fnid INTEGER PRIMARY KEY, -- Filename ID @ name TEXT UNIQUE -- Name of file page @ ); @ @ @ -- A "file class" is like a filename except that it remains constant @ -- across renames. @ -- @ CREATE TABLE fileclass( @ fclass INTEGER PRIMARY KEY, -- Unique id for this fileclass @ ckid INTEGER REFERENCES plink(cid), -- Checkin where file originates @ fnid INTEGER REFERENCES filename -- Name of the file in ckid @ ); @ @ -- Linkages between checkins, files created by each checkin, and @ -- the names of those files. @ -- @ -- Each entry represents a file that changed content from pid to fid @ -- due to the check-in that goes from pmid to mid. fnid is the name @ -- of the file in the mid check-in. If the file was renamed as part @ -- of the mid check-in, then pfnid is the previous filename. @ @ -- There can be multiple entries for (mid,fid) if the mid checkin was @ -- a merge. Entries with isaux==0 are from the primary parent. Merge @ -- parents have isaux set to true. @ -- @ -- pid==0 if the file is added by checkin mid. @ -- fid==0 if the file is removed by checkin mid. @ -- @ CREATE TABLE mlink( @ mid INTEGER REFERENCES plink(cid), -- Checkin that contains fid @ fid INTEGER REFERENCES blob, -- New file content. 0 if deleted @ pmid INTEGER REFERENCES plink(cid), -- Checkin that contains pid @ pid INTEGER REFERENCES blob, -- Prev file content. 0 if new @ fnid INTEGER REFERENCES filename, -- Name of the file @ pfnid INTEGER REFERENCES filename, -- Previous name. 0 if unchanged @ mperm INTEGER, -- File permissions. 1==exec @ fclass INTEGER REFERENCE fileclass, -- fid is an instance of this class @ isaux BOOLEAN DEFAULT 0 -- TRUE if pmid is the primary @ ); @ CREATE INDEX mlink_i1 ON mlink(mid); @ CREATE INDEX mlink_i2 ON mlink(fnid); @ CREATE INDEX mlink_i3 ON mlink(fid); @ CREATE INDEX mlink_i4 ON mlink(pid); @ @ -- Parent/child linkages between checkins @ -- @ CREATE TABLE plink( @ pid INTEGER REFERENCES blob, -- Parent manifest @ cid INTEGER REFERENCES blob, -- Child manifest @ isprim BOOLEAN, -- pid is the primary parent of cid @ mtime DATETIME, -- the date/time stamp on cid. Julian day. @ baseid INTEGER REFERENCES blob, -- Baseline if cid is a delta manifest. @ UNIQUE(pid, cid) @ ); @ CREATE INDEX plink_i2 ON plink(cid,pid); @ @ -- A "leaf" checkin is a checkin that has no children in the same @ -- branch. The set of all leaves is easily computed with a join, @ -- between the plink and tagxref tables, but it is a slower join for |
| ︙ | ︙ | |||
486 487 488 489 490 491 492 | @ -- done by an --integrate merge. The difference between vfile.chnged==3|5 @ -- and a regular add is that with vfile.chnged==3|5 we know that the @ -- current version of the file is already in the repository. @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | @ -- done by an --integrate merge. The difference between vfile.chnged==3|5 @ -- and a regular add is that with vfile.chnged==3|5 we know that the @ -- current version of the file is already in the repository. @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ islink BOOLEAN, -- True if file should be symlink @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root |
| ︙ | ︙ |