2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
25 #include "poolid_private.h"
28 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
29 unsigned char *out, unsigned int out_len);
30 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
33 unsigned int out_len);
37 repodata_free(Repodata *data)
40 sat_free(data->schemata);
41 sat_free(data->schemadata);
43 sat_free(data->spool.strings);
44 sat_free(data->spool.stringspace);
45 sat_free(data->spool.stringhashtbl);
47 sat_free(data->dirpool.dirs);
48 sat_free(data->dirpool.dirtraverse);
50 sat_free(data->incoredata);
51 sat_free(data->incoreoffset);
52 sat_free(data->verticaloffset);
54 sat_free(data->blob_store);
55 sat_free(data->pages);
56 sat_free(data->mapped);
58 sat_free(data->vincore);
60 sat_free(data->attrs);
61 sat_free(data->attrdata);
62 sat_free(data->attriddata);
68 static unsigned char *
69 data_read_id(unsigned char *dp, Id *idp)
81 x = (x << 7) ^ c ^ 128;
85 static unsigned char *
86 data_read_ideof(unsigned char *dp, Id *idp, int *eof)
105 x = (x << 7) ^ c ^ 128;
109 static unsigned char *
110 data_skip(unsigned char *dp, int type)
121 while ((*dp & 0x80) != 0)
125 while ((*dp & 0xc0) != 0)
132 case TYPE_DIRSTRARRAY:
135 while ((*dp & 0x80) != 0)
144 case TYPE_DIRNUMNUMARRAY:
147 while ((*dp & 0x80) != 0)
150 while ((*dp & 0x80) != 0)
153 while ((*dp & 0x80) != 0)
160 fprintf(stderr, "unknown type in data_skip\n");
165 static unsigned char *
166 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
179 kv->str = (const char *)dp;
180 return dp + strlen(kv->str) + 1;
182 return data_read_id(dp, &kv->id);
184 return data_read_id(dp, &kv->num);
186 return data_read_ideof(dp, &kv->id, &kv->eof);
188 return data_read_id(dp, &kv->id);
189 case TYPE_DIRSTRARRAY:
190 dp = data_read_ideof(dp, &kv->id, &kv->eof);
191 kv->str = (const char *)dp;
192 return dp + strlen(kv->str) + 1;
193 case TYPE_DIRNUMNUMARRAY:
194 dp = data_read_id(dp, &kv->id);
195 dp = data_read_id(dp, &kv->num);
196 return data_read_ideof(dp, &kv->num2, &kv->eof);
202 static unsigned char *
203 forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp)
207 keyp = data->schemadata + data->schemata[schemaid];
208 while ((k = *keyp++) != 0)
212 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
214 dp = data_skip(dp, TYPE_ID); /* skip that offset */
215 dp = data_skip(dp, TYPE_ID); /* skip that length */
218 if (data->keys[k].storage != KEY_STORAGE_INCORE)
220 dp = data_skip(dp, data->keys[k].type);
225 #define BLOB_PAGEBITS 15
226 #define BLOB_PAGESIZE (1 << BLOB_PAGEBITS)
228 static unsigned char *
229 load_page_range(Repodata *data, unsigned int pstart, unsigned int pend)
231 /* Make sure all pages from PSTART to PEND (inclusive) are loaded,
232 and are consecutive. Return a pointer to the mapping of PSTART. */
233 unsigned char buf[BLOB_PAGESIZE];
236 /* Quick check in case all pages are there already and consecutive. */
237 for (i = pstart; i <= pend; i++)
238 if (data->pages[i].mapped_at == -1
240 && data->pages[i].mapped_at
241 != data->pages[i-1].mapped_at + BLOB_PAGESIZE))
244 return data->blob_store + data->pages[pstart].mapped_at;
246 /* Ensure that we can map the numbers of pages we need at all. */
247 if (pend - pstart + 1 > data->ncanmap)
249 unsigned int oldcan = data->ncanmap;
250 data->ncanmap = pend - pstart + 1;
251 if (data->ncanmap < 4)
253 data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0]));
254 memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0]));
255 data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE);
257 fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap);
261 /* Now search for "cheap" space in our store. Space is cheap if it's either
262 free (very cheap) or contains pages we search for anyway. */
264 /* Setup cost array. */
265 unsigned int cost[data->ncanmap];
266 for (i = 0; i < data->ncanmap; i++)
268 unsigned int pnum = data->mapped[i];
274 Attrblobpage *p = data->pages + pnum;
275 assert (p->mapped_at != -1);
276 if (pnum >= pstart && pnum <= pend)
283 /* And search for cheapest space. */
284 unsigned int best_cost = -1;
285 unsigned int best = 0;
286 unsigned int same_cost = 0;
287 for (i = 0; i + pend - pstart < data->ncanmap; i++)
289 unsigned int c = cost[i];
291 for (j = 0; j < pend - pstart + 1; j++)
294 best_cost = c, best = i;
295 else if (c == best_cost)
297 /* A null cost won't become better. */
301 /* If all places have the same cost we would thrash on slot 0. Avoid
302 this by doing a round-robin strategy in this case. */
303 if (same_cost == data->ncanmap - pend + pstart - 1)
304 best = data->rr_counter++ % (data->ncanmap - pend + pstart);
306 /* So we want to map our pages from [best] to [best+pend-pstart].
307 Use a very simple strategy, which doesn't make the best use of
308 our resources, but works. Throw away all pages in that range
309 (even ours) then copy around ours (in case they were outside the
310 range) or read them in. */
311 for (i = best; i < best + pend - pstart + 1; i++)
313 unsigned int pnum = data->mapped[i];
315 /* If this page is exactly at the right place already,
316 no need to evict it. */
317 && pnum != pstart + i - best)
319 /* Evict this page. */
321 fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i);
325 data->pages[pnum].mapped_at = -1;
329 /* Everything is free now. Read in the pages we want. */
330 for (i = pstart; i <= pend; i++)
332 Attrblobpage *p = data->pages + i;
333 unsigned int pnum = i - pstart + best;
334 void *dest = data->blob_store + pnum * BLOB_PAGESIZE;
335 if (p->mapped_at != -1)
337 if (p->mapped_at != pnum * BLOB_PAGESIZE)
340 fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum);
342 /* Still mapped somewhere else, so just copy it from there. */
343 memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE);
344 data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0;
349 unsigned int in_len = p->file_size;
350 unsigned int compressed = in_len & 1;
353 fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
355 /* Not mapped, so read in this page. */
356 if (fseek(data->fp, p->file_offset, SEEK_SET) < 0)
358 perror ("mapping fseek");
361 if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
363 perror ("mapping fread");
368 unsigned int out_len;
369 out_len = unchecked_decompress_buf(buf, in_len,
370 dest, BLOB_PAGESIZE);
371 if (out_len != BLOB_PAGESIZE
372 && i < data->num_pages - 1)
374 fprintf (stderr, "can't decompress\n");
378 fprintf (stderr, " (expand %d to %d)", in_len, out_len);
382 fprintf (stderr, "\n");
385 p->mapped_at = pnum * BLOB_PAGESIZE;
386 data->mapped[pnum] = i + 1;
388 return data->blob_store + best * BLOB_PAGESIZE;
391 static unsigned char *
392 make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
395 if (key->type == TYPE_VOID)
397 if (off >= data->lastverticaloffset)
399 off -= data->lastverticaloffset;
400 if (off + len > data->vincorelen)
402 return data->vincore + off;
406 if (off + len > key->size)
408 /* we now have the offset, go into vertical */
409 off += data->verticaloffset[key - data->keys];
410 dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
412 dp += off % BLOB_PAGESIZE;
416 static inline unsigned char *
417 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
419 unsigned char *dp = *dpp;
423 if (key->storage == KEY_STORAGE_INCORE)
425 /* hmm, this is a bit expensive */
426 *dpp = data_skip(dp, key->type);
429 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
432 dp = data_read_id(dp, &off);
433 dp = data_read_id(dp, &len);
435 return make_vertical_available(data, key, off, len);
441 maybe_load_repodata(Repodata *data)
443 if (data->state == REPODATA_STUB)
445 if (data->loadcallback)
446 data->loadcallback(data);
448 data->state = REPODATA_ERROR;
450 if (data->state == REPODATA_AVAILABLE)
452 data->state = REPODATA_ERROR;
457 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
464 if (!maybe_load_repodata (data))
467 dp = data->incoredata + data->incoreoffset[entry];
468 dp = data_read_id(dp, &schema);
469 /* make sure the schema of this solvable contains the key */
470 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
473 dp = forward_to_key(data, keyid, schema, dp);
474 key = data->keys + keyid;
475 dp = get_data(data, key, &dp);
478 if (key->type == TYPE_STR)
479 return (const char *)dp;
480 if (key->type != TYPE_ID)
482 /* id type, must either use global or local string store*/
483 dp = data_read_id(dp, &id);
485 return data->spool.stringspace + data->spool.strings[id];
486 return id2str(data->repo->pool, id);
490 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
500 if (!maybe_load_repodata (data))
503 dp = data->incoredata + data->incoreoffset[entry];
504 dp = data_read_id(dp, &schema);
505 /* make sure the schema of this solvable contains the key */
506 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
509 dp = forward_to_key(data, keyid, schema, dp);
510 key = data->keys + keyid;
511 dp = get_data(data, key, &dp);
514 if (key->type == TYPE_NUM
515 || key->type == TYPE_U32
516 || key->type == TYPE_CONSTANT)
518 dp = data_fetch(dp, &kv, key);
526 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
530 Id k, keyid, *kp, *keyp;
531 unsigned char *dp, *ddp;
536 if (!maybe_load_repodata (data))
539 dp = data->incoredata + data->incoreoffset[entry];
540 dp = data_read_id(dp, &schema);
541 keyp = data->schemadata + data->schemata[schema];
544 /* search in a specific key */
545 for (kp = keyp; (k = *kp++) != 0; )
546 if (data->keys[k].name == keyname)
550 dp = forward_to_key(data, k, schema, dp);
556 while ((keyid = *keyp++) != 0)
559 key = data->keys + keyid;
560 ddp = get_data(data, key, &dp);
563 ddp = data_fetch(ddp, &kv, key);
566 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
568 while (!kv.eof && !stop);
569 if (onekey || stop > SEARCH_NEXT_KEY)
575 /* extend repodata so that it includes solvables p */
577 repodata_extend(Repodata *data, Id p)
579 if (data->start == data->end)
580 data->start = data->end = p;
583 int old = data->end - data->start;
584 int new = p - data->end + 1;
587 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
588 memset(data->attrs + old, 0, new * sizeof(Id *));
590 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
591 memset(data->incoreoffset + old, 0, new * sizeof(Id));
596 int old = data->end - data->start;
597 int new = data->start - p;
600 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
601 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
602 memset(data->attrs, 0, new * sizeof(Id *));
604 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
605 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
606 memset(data->incoreoffset, 0, new * sizeof(Id));
612 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
617 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
619 if (data->attrs[entry])
621 for (pp = data->attrs[entry]; *pp; pp += 2)
622 /* Determine equality based on the name only, allows us to change
623 type (when overwrite is set), and makes TYPE_CONSTANT work. */
624 if (data->keys[*pp].name == data->keys[keyid].name)
635 i = pp - data->attrs[entry];
637 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
638 pp = data->attrs[entry] + i;
645 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
649 /* find key in keys */
650 for (keyid = 1; keyid < data->nkeys; keyid++)
651 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
653 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
657 if (keyid == data->nkeys)
659 /* allocate new key */
660 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
661 data->keys[data->nkeys++] = *key;
662 if (data->verticaloffset)
664 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
665 data->verticaloffset[data->nkeys - 1] = 0;
668 repodata_insert_keyid(data, entry, keyid, val, 1);
672 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
678 key.storage = KEY_STORAGE_INCORE;
679 repodata_set(data, entry, &key, id);
683 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
689 key.storage = KEY_STORAGE_INCORE;
690 repodata_set(data, entry, &key, num);
694 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
699 id = stringpool_str2id(&data->spool, str, 1);
701 id = str2id(data->repo->pool, str, 1);
705 key.storage = KEY_STORAGE_INCORE;
706 repodata_set(data, entry, &key, id);
710 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
714 key.type = TYPE_CONSTANT;
716 key.storage = KEY_STORAGE_INCORE;
717 repodata_set(data, entry, &key, 0);
721 repodata_set_void(Repodata *data, Id entry, Id keyname)
725 key.type = TYPE_VOID;
727 key.storage = KEY_STORAGE_INCORE;
728 repodata_set(data, entry, &key, 0);
732 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
741 key.storage = KEY_STORAGE_INCORE;
742 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
743 memcpy(data->attrdata + data->attrdatalen, str, l);
744 repodata_set(data, entry, &key, data->attrdatalen);
745 data->attrdatalen += l;
749 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
755 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
757 if (data->attrs && data->attrs[entry])
759 for (pp = data->attrs[entry]; *pp; pp += 2)
760 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
765 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
767 if (ida + 1 == data->attriddata + data->attriddatalen)
769 /* this was the last entry, just append it */
770 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
771 data->attriddatalen--; /* overwrite terminating 0 */
775 /* too bad. move to back. */
776 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
777 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
778 pp[1] = data->attriddatalen;
779 data->attriddatalen += oldsize;
781 data->attriddata[data->attriddatalen++] = dir;
782 data->attriddata[data->attriddatalen++] = num;
783 data->attriddata[data->attriddatalen++] = num2;
784 data->attriddata[data->attriddatalen++] = 0;
789 key.type = TYPE_DIRNUMNUMARRAY;
791 key.storage = KEY_STORAGE_INCORE;
792 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
793 repodata_set(data, entry, &key, data->attriddatalen);
794 data->attriddata[data->attriddatalen++] = dir;
795 data->attriddata[data->attriddatalen++] = num;
796 data->attriddata[data->attriddatalen++] = num2;
797 data->attriddata[data->attriddatalen++] = 0;
801 repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
803 Id *ida, *pp, stroff;
808 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
809 memcpy(data->attrdata + data->attrdatalen, str, l);
810 stroff = data->attrdatalen;
811 data->attrdatalen += l;
814 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str, data->attriddatalen);
816 if (data->attrs && data->attrs[entry])
818 for (pp = data->attrs[entry]; *pp; pp += 2)
819 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRSTRARRAY)
824 for (ida = data->attriddata + pp[1]; *ida; ida += 2)
826 if (ida + 1 == data->attriddata + data->attriddatalen)
828 /* this was the last entry, just append it */
829 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 2, sizeof(Id));
830 data->attriddatalen--; /* overwrite terminating 0 */
834 /* too bad. move to back. */
835 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 3, sizeof(Id));
836 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
837 pp[1] = data->attriddatalen;
838 data->attriddatalen += oldsize;
840 data->attriddata[data->attriddatalen++] = dir;
841 data->attriddata[data->attriddatalen++] = stroff;
842 data->attriddata[data->attriddatalen++] = 0;
847 key.type = TYPE_DIRSTRARRAY;
849 key.storage = KEY_STORAGE_INCORE;
850 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
851 repodata_set(data, entry, &key, data->attriddatalen);
852 data->attriddata[data->attriddatalen++] = dir;
853 data->attriddata[data->attriddatalen++] = stroff;
854 data->attriddata[data->attriddatalen++] = 0;
858 repodata_merge_attrs (Repodata *data, Id dest, Id src)
861 for (keyp = data->attrs[src]; *keyp; keyp += 2)
862 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
865 /*********************************/
867 /* unify with repo_write! */
869 #define EXTDATA_BLOCK 1023
870 #define SCHEMATA_BLOCK 31
871 #define SCHEMATADATA_BLOCK 255
879 data_addid(struct extdata *xd, Id x)
882 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
883 dp = xd->buf + xd->len;
888 *dp++ = (x >> 28) | 128;
890 *dp++ = (x >> 21) | 128;
891 *dp++ = (x >> 14) | 128;
894 *dp++ = (x >> 7) | 128;
896 xd->len = dp - xd->buf;
900 data_addideof(struct extdata *xd, Id x, int eof)
903 x = (x & 63) | ((x & ~63) << 1);
904 data_addid(xd, (eof ? x: x | 64));
908 data_addblob(struct extdata *xd, unsigned char *blob, int len)
910 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
911 memcpy(xd->buf + xd->len, blob, len);
915 /*********************************/
918 addschema_prepare(Repodata *data, Id *schematacache)
923 memset(schematacache, 0, 256 * sizeof(Id));
924 for (i = 0; i < data->nschemata; i++)
926 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
929 schematacache[h] = i + 1;
931 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
932 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
936 addschema(Repodata *data, Id *schema, Id *schematacache)
941 for (sp = schema, len = 0, h = 0; *sp; len++)
946 cid = schematacache[h];
950 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
953 for (cid = 0; cid < data->nschemata; cid++)
954 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
957 /* a new one. make room. */
958 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
959 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
961 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
962 data->schemata[data->nschemata] = data->schemadatalen;
963 data->schemadatalen += len;
964 schematacache[h] = data->nschemata + 1;
966 fprintf(stderr, "addschema: new schema\n");
968 return data->nschemata++;
973 repodata_internalize(Repodata *data)
976 Id id, entry, nentry, *ida;
977 Id schematacache[256];
978 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
979 unsigned char *dp, *ndp;
980 int newschema, oldcount;
981 struct extdata newincore;
982 struct extdata newvincore;
987 newvincore.buf = data->vincore;
988 newvincore.len = data->vincorelen;
990 schema = sat_malloc2(data->nkeys, sizeof(Id));
991 seen = sat_malloc2(data->nkeys, sizeof(Id));
993 /* Merge the data already existing (in data->schemata, ->incoredata and
994 friends) with the new attributes in data->attrs[]. */
995 nentry = data->end - data->start;
996 addschema_prepare(data, schematacache);
997 memset(&newincore, 0, sizeof(newincore));
998 for (entry = 0; entry < nentry; entry++)
1000 memset(seen, 0, data->nkeys * sizeof(Id));
1002 dp = data->incoredata + data->incoreoffset[entry];
1003 if (data->incoredata)
1004 dp = data_read_id(dp, &oldschema);
1008 fprintf(stderr, "oldschema %d\n", oldschema);
1009 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
1010 fprintf(stderr, "schemadata %p\n", data->schemadata);
1012 /* seen: -1: old data 0: skipped >0: id + 1 */
1015 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
1019 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
1026 if (data->attrs[entry])
1027 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
1034 seen[*keyp] = keyp[1] + 1;
1038 /* Ideally we'd like to sort the new schema here, to ensure
1039 schema equality independend of the ordering. We can't do that
1040 yet. For once see below (old ids need to come before new ids).
1041 An additional difficulty is that we also need to move
1042 the values with the keys. */
1043 schemaid = addschema(data, schema, schematacache);
1045 schemaid = oldschema;
1048 /* Now create data blob. We walk through the (possibly new) schema
1049 and either copy over old data, or insert the new. */
1050 /* XXX Here we rely on the fact that the (new) schema has the form
1051 o1 o2 o3 o4 ... | n1 n2 n3 ...
1052 (oX being the old keyids (possibly overwritten), and nX being
1053 the new keyids). This rules out sorting the keyids in order
1054 to ensure a small schema count. */
1055 data->incoreoffset[entry] = newincore.len;
1056 data_addid(&newincore, schemaid);
1057 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
1059 key = data->keys + *keyp;
1063 /* Skip the data associated with this old key. */
1064 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1066 ndp = data_skip(dp, TYPE_ID);
1067 ndp = data_skip(ndp, TYPE_ID);
1069 else if (key->storage == KEY_STORAGE_INCORE)
1070 ndp = data_skip(dp, key->type);
1073 if (seen[*keyp] == -1)
1075 /* If this key was an old one _and_ was not overwritten with
1076 a different value copy over the old value (we skipped it
1079 data_addblob(&newincore, dp, ndp - dp);
1082 else if (seen[*keyp])
1084 /* Otherwise we have a new value. Parse it into the internal
1087 unsigned int oldvincorelen = 0;
1090 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1093 oldvincorelen = xd->len;
1095 id = seen[*keyp] - 1;
1102 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1109 case TYPE_DIRNUMNUMARRAY:
1110 for (ida = data->attriddata + id; *ida; ida += 3)
1112 data_addid(xd, ida[0]);
1113 data_addid(xd, ida[1]);
1114 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1117 case TYPE_DIRSTRARRAY:
1118 for (ida = data->attriddata + id; *ida; ida += 2)
1120 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1121 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1125 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1128 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1130 /* put offset/len in incore */
1131 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1132 oldvincorelen = xd->len - oldvincorelen;
1133 data_addid(&newincore, oldvincorelen);
1139 data->incoredata = newincore.buf;
1140 data->incoredatalen = newincore.len;
1141 data->incoredatafree = 0;
1143 data->vincore = newvincore.buf;
1144 data->vincorelen = newvincore.len;
1146 data->attrs = sat_free(data->attrs);
1147 data->attrdata = sat_free(data->attrdata);
1148 data->attrdatalen = 0;
1152 repodata_str2dir(Repodata *data, const char *dir, int create)
1158 while (*dir == '/' && dir[1] == '/')
1162 dire = strchrnul(dir, '/');
1163 if (data->localpool)
1164 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1166 id = strn2id(data->repo->pool, dir, dire - dir, create);
1169 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1182 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1184 return compress_buf(page, len, cpage, max);
1187 #define SOLV_ERROR_EOF 3
1189 static inline unsigned int
1195 for (i = 0; i < 4; i++)
1205 /* Try to either setup on-demand paging (using FP as backing
1206 file), or in case that doesn't work (FP not seekable) slurps in
1207 all pages and deactivates paging. */
1210 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1212 FILE *fp = data->fp;
1213 unsigned int npages;
1215 unsigned int can_seek;
1217 unsigned char buf[BLOB_PAGESIZE];
1218 if (pagesz != BLOB_PAGESIZE)
1220 /* We could handle this by slurping in everything. */
1221 fprintf (stderr, "non matching page size\n");
1225 if ((cur_file_ofs = ftell(fp)) < 0)
1229 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1231 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1233 data->num_pages = npages;
1234 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1236 /* If we can't seek on our input we have to slurp in everything. */
1238 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1239 for (i = 0; i < npages; i++)
1241 unsigned int in_len = read_u32(fp);
1242 unsigned int compressed = in_len & 1;
1243 Attrblobpage *p = data->pages + i;
1246 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1247 i, in_len, compressed ? "" : "not ");
1253 p->file_offset = cur_file_ofs;
1254 p->file_size = in_len * 2 + compressed;
1255 if (fseek(fp, in_len, SEEK_CUR) < 0)
1258 fprintf (stderr, "can't seek after we thought we can\n");
1259 /* We can't fall back to non-seeking behaviour as we already
1260 read over some data pages without storing them away. */
1263 cur_file_ofs += in_len;
1267 unsigned int out_len;
1268 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1269 p->mapped_at = i * BLOB_PAGESIZE;
1272 /* We can't seek, so suck everything in. */
1273 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1280 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1281 if (out_len != BLOB_PAGESIZE
1284 fprintf (stderr, "can't decompress\n");
1293 /* If we are here we were able to seek to all page
1294 positions, so activate paging by copying FP into our structure.
1295 We dup() the file, so that our callers can fclose() it and we
1296 still have it open. But this means that we share file positions
1297 with the input filedesc. So in case our caller reads it after us,
1298 and calls back into us we might change the file position unexpectedly
1300 int fd = dup (fileno (fp));
1303 /* Jeez! What a bloody system, we can't dup() anymore. */
1307 /* XXX we don't close this yet anywhere. */
1308 data->fp = fdopen (fd, "r");
1311 /* My God! What happened now? */