Fossil SCM

fossil-scm / src / pivot.c
Blame History Raw 206 lines
1
/*
2
** Copyright (c) 2007 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This file contains code used to find the most recent common
19
** ancestor of time versions of the same file. We call this
20
** common ancestor the "pivot" in a 3-way merge.
21
*/
22
#include "config.h"
23
#include "pivot.h"
24
#include <assert.h>
25
26
27
/*
28
** Set the primary file. The primary version is one of the two
29
** files that have a common ancestor. The other file is the secondary.
30
** There can be multiple secondaries but only a single primary.
31
** The primary must be set first.
32
**
33
** In the merge algorithm, the file being merged in is the primary.
34
** The current check-out or other files that have been merged into
35
** the current check-out are the secondaries.
36
**
37
** The act of setting the primary resets the pivot-finding algorithm.
38
*/
39
void pivot_set_primary(int rid){
40
/* Set up table used to do the search */
41
db_multi_exec(
42
"CREATE TEMP TABLE IF NOT EXISTS aqueue("
43
" rid INTEGER," /* The record id for this version */
44
" mtime REAL," /* Time when this version was created */
45
" pending BOOLEAN," /* True if we have not check this one yet */
46
" src BOOLEAN," /* 1 for primary. 0 for others */
47
" PRIMARY KEY(rid,src)"
48
") WITHOUT ROWID;"
49
"DELETE FROM aqueue;"
50
"CREATE INDEX IF NOT EXISTS aqueue_idx1 ON aqueue(pending, mtime);"
51
);
52
53
/* Insert the primary record */
54
db_multi_exec(
55
"INSERT INTO aqueue(rid, mtime, pending, src)"
56
" SELECT %d, mtime, 1, 1 FROM event WHERE objid=%d AND type='ci' LIMIT 1",
57
rid, rid
58
);
59
}
60
61
/*
62
** Set a secondary file. The primary file must be set first. There
63
** must be at least one secondary but there can be more than one if
64
** desired.
65
*/
66
void pivot_set_secondary(int rid){
67
/* Insert the secondary record */
68
db_multi_exec(
69
"INSERT OR IGNORE INTO aqueue(rid, mtime, pending, src)"
70
" SELECT %d, mtime, 1, 0 FROM event WHERE objid=%d AND type='ci'",
71
rid, rid
72
);
73
}
74
75
/*
76
** Find the most recent common ancestor of the primary and one of
77
** the secondaries. Return its rid. Return 0 if no common ancestor
78
** can be found.
79
**
80
** If ignoreMerges is true, follow only "primary" parent links.
81
*/
82
int pivot_find(int ignoreMerges){
83
Stmt q1, q2, u1, i1;
84
int rid = 0;
85
86
/* aqueue must contain at least one primary and one other. Otherwise
87
** we abort early
88
*/
89
if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
90
fossil_fatal("lack both primary and secondary files");
91
}
92
93
/* Prepare queries we will be needing
94
**
95
** The first query finds the oldest pending version on the aqueue. This
96
** will be next one searched.
97
*/
98
db_prepare(&q1, "SELECT rid FROM aqueue WHERE pending"
99
" ORDER BY pending DESC, mtime DESC");
100
101
/* Check to see if the record :rid is a common ancestor. The result
102
** set contains one or more rows if it is and is the empty set if it
103
** is not.
104
*/
105
db_prepare(&q2,
106
"SELECT 1 FROM aqueue A, plink, aqueue B"
107
" WHERE plink.pid=:rid"
108
" AND plink.cid=B.rid"
109
" AND A.rid=:rid"
110
" AND A.src!=B.src %s",
111
ignoreMerges ? "AND plink.isprim" : ""
112
);
113
114
/* Mark the :rid record has having been checked. It is not the
115
** common ancestor.
116
*/
117
db_prepare(&u1,
118
"UPDATE aqueue SET pending=0 WHERE rid=:rid"
119
);
120
121
/* Add to the queue all ancestors of :rid.
122
*/
123
db_prepare(&i1,
124
"REPLACE INTO aqueue "
125
"SELECT plink.pid,"
126
" coalesce((SELECT mtime FROM event X WHERE X.objid=plink.pid), 0.0),"
127
" 1,"
128
" aqueue.src "
129
" FROM plink, aqueue"
130
" WHERE plink.cid=:rid"
131
" AND aqueue.rid=:rid %s",
132
ignoreMerges ? "AND plink.isprim" : ""
133
);
134
135
while( db_step(&q1)==SQLITE_ROW ){
136
rid = db_column_int(&q1, 0);
137
db_reset(&q1);
138
db_bind_int(&q2, ":rid", rid);
139
if( db_step(&q2)==SQLITE_ROW ){
140
break;
141
}
142
db_reset(&q2);
143
db_bind_int(&i1, ":rid", rid);
144
db_exec(&i1);
145
db_bind_int(&u1, ":rid", rid);
146
db_exec(&u1);
147
rid = 0;
148
}
149
db_finalize(&q1);
150
db_finalize(&q2);
151
db_finalize(&i1);
152
db_finalize(&u1);
153
return rid;
154
}
155
156
/*
157
** COMMAND: merge-base
158
**
159
** Usage: %fossil merge-base ?options? PRIMARY SECONDARY ...
160
**
161
** Find a common ancestor given two or more check-in versions to
162
** hypothetically merge.
163
**
164
** Options:
165
** --ignore-merges Ignore merges for discovering name pivots
166
*/
167
void merge_base_cmd(void){
168
int i, rid;
169
int ignoreMerges = find_option("ignore-merges",0,0)!=0;
170
int showDetails = find_option("details",0,0)!=0
171
/* intentionally undocumented */;
172
if( g.argc<4 ){
173
usage("?options? PRIMARY SECONDARY ...");
174
}
175
db_must_be_within_tree();
176
pivot_set_primary(name_to_rid(g.argv[2]));
177
for(i=3; i<g.argc; i++){
178
pivot_set_secondary(name_to_rid(g.argv[i]));
179
}
180
rid = pivot_find(ignoreMerges);
181
if( rid==0 ){
182
puts("No common ancestor found.");
183
}else{
184
printf("pivot=%s\n",
185
db_text("?","SELECT uuid FROM blob WHERE rid=%d",rid));
186
}
187
if( showDetails ){
188
Stmt q;
189
db_prepare(&q,
190
"SELECT substr(uuid,1,12), aqueue.rid, datetime(aqueue.mtime),"
191
" aqueue.pending, aqueue.src\n"
192
" FROM aqueue JOIN blob ON aqueue.rid=blob.rid\n"
193
" ORDER BY aqueue.mtime DESC"
194
);
195
while( db_step(&q)==SQLITE_ROW ){
196
printf("\"%s\",%d,\"%s\",%d,%d\n",
197
db_column_text(&q, 0),
198
db_column_int(&q, 1),
199
db_column_text(&q, 2),
200
db_column_int(&q, 3),
201
db_column_int(&q, 4));
202
}
203
db_finalize(&q);
204
}
205
}
206

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button