[PATCH] Parallelize the pull algorithm
[git.git] / pull.c
1 #include "pull.h"
2
3 #include "cache.h"
4 #include "commit.h"
5 #include "tree.h"
6 #include "tag.h"
7 #include "blob.h"
8 #include "refs.h"
9
10 const char *write_ref = NULL;
11
12 const unsigned char *current_ref = NULL;
13
14 int get_tree = 0;
15 int get_history = 0;
16 int get_all = 0;
17 int get_verbosely = 0;
18 static unsigned char current_commit_sha1[20];
19
20 void pull_say(const char *fmt, const char *hex) 
21 {
22         if (get_verbosely)
23                 fprintf(stderr, fmt, hex);
24 }
25
26 static void report_missing(const char *what, const unsigned char *missing)
27 {
28         char missing_hex[41];
29
30         strcpy(missing_hex, sha1_to_hex(missing));;
31         fprintf(stderr,
32                 "Cannot obtain needed %s %s\nwhile processing commit %s.\n",
33                 what, missing_hex, sha1_to_hex(current_commit_sha1));
34 }
35
36 static int make_sure_we_have_it(const char *what, unsigned char *sha1)
37 {
38         int status = 0;
39
40         if (!has_sha1_file(sha1)) {
41                 status = fetch(sha1);
42                 if (status && what)
43                         report_missing(what, sha1);
44         }
45         return status;
46 }
47
48 static int process(unsigned char *sha1, const char *type);
49
50 static int process_tree(struct tree *tree)
51 {
52         struct tree_entry_list *entries;
53
54         if (parse_tree(tree))
55                 return -1;
56
57         for (entries = tree->entries; entries; entries = entries->next) {
58                 if (process(entries->item.any->sha1,
59                             entries->directory ? tree_type : blob_type))
60                         return -1;
61         }
62         return 0;
63 }
64
65 static int process_commit(struct commit *commit)
66 {
67         if (parse_commit(commit))
68                 return -1;
69
70         memcpy(current_commit_sha1, commit->object.sha1, 20);
71
72         if (get_tree) {
73                 if (process(commit->tree->object.sha1, tree_type))
74                         return -1;
75                 if (!get_all)
76                         get_tree = 0;
77         }
78         if (get_history) {
79                 struct commit_list *parents = commit->parents;
80                 for (; parents; parents = parents->next) {
81                         if (has_sha1_file(parents->item->object.sha1))
82                                 continue;
83                         if (process(parents->item->object.sha1,
84                                     commit_type))
85                                 return -1;
86                 }
87         }
88         return 0;
89 }
90
91 static int process_tag(struct tag *tag)
92 {
93         if (parse_tag(tag))
94                 return -1;
95         return process(tag->tagged->sha1, NULL);
96 }
97
98 static struct object_list *process_queue = NULL;
99 static struct object_list **process_queue_end = &process_queue;
100
101 static int process(unsigned char *sha1, const char *type)
102 {
103         struct object *obj;
104         if (has_sha1_file(sha1))
105                 return 0;
106         obj = lookup_object_type(sha1, type);
107         if (object_list_contains(process_queue, obj))
108                 return 0;
109         object_list_insert(obj, process_queue_end);
110         process_queue_end = &(*process_queue_end)->next;
111
112         //fprintf(stderr, "prefetch %s\n", sha1_to_hex(sha1));
113         prefetch(sha1);
114                 
115         return 0;
116 }
117
118 static int loop(void)
119 {
120         while (process_queue) {
121                 struct object *obj = process_queue->item;
122                 /*
123                 fprintf(stderr, "%d objects to pull\n", 
124                         object_list_length(process_queue));
125                 */
126                 process_queue = process_queue->next;
127                 if (!process_queue)
128                         process_queue_end = &process_queue;
129
130                 //fprintf(stderr, "fetch %s\n", sha1_to_hex(obj->sha1));
131                 
132                 if (make_sure_we_have_it(obj->type ?: "object", 
133                                          obj->sha1))
134                         return -1;
135                 if (!obj->type)
136                         parse_object(obj->sha1);
137                 if (obj->type == commit_type) {
138                         if (process_commit((struct commit *)obj))
139                                 return -1;
140                         continue;
141                 }
142                 if (obj->type == tree_type) {
143                         if (process_tree((struct tree *)obj))
144                                 return -1;
145                         continue;
146                 }
147                 if (obj->type == blob_type) {
148                         continue;
149                 }
150                 if (obj->type == tag_type) {
151                         if (process_tag((struct tag *)obj))
152                                 return -1;
153                         continue;
154                 }
155                 return error("Unable to determine requirements "
156                              "of type %s for %s",
157                              obj->type, sha1_to_hex(obj->sha1));
158         }
159         return 0;
160 }
161
162 static int interpret_target(char *target, unsigned char *sha1)
163 {
164         if (!get_sha1_hex(target, sha1))
165                 return 0;
166         if (!check_ref_format(target)) {
167                 if (!fetch_ref(target, sha1)) {
168                         return 0;
169                 }
170         }
171         return -1;
172 }
173
174
175 int pull(char *target)
176 {
177         unsigned char sha1[20];
178         int fd = -1;
179
180         if (write_ref && current_ref) {
181                 fd = lock_ref_sha1(write_ref, current_ref);
182                 if (fd < 0)
183                         return -1;
184         }
185
186         if (interpret_target(target, sha1))
187                 return error("Could not interpret %s as something to pull",
188                              target);
189         if (process(sha1, NULL))
190                 return -1;
191         if (loop())
192                 return -1;
193         
194         if (write_ref) {
195                 if (current_ref) {
196                         write_ref_sha1(write_ref, fd, sha1);
197                 } else {
198                         write_ref_sha1_unlocked(write_ref, sha1);
199                 }
200         }
201         return 0;
202 }