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);
35 static unsigned char *
36 data_read_id(unsigned char *dp, Id *idp)
48 x = (x << 7) ^ c ^ 128;
52 static unsigned char *
53 data_read_ideof(unsigned char *dp, Id *idp, int *eof)
72 x = (x << 7) ^ c ^ 128;
76 static unsigned char *
77 data_skip(unsigned char *dp, int type)
88 while ((*dp & 0x80) != 0)
92 while ((*dp & 0xc0) != 0)
99 case TYPE_DIRSTRARRAY:
102 while ((*dp & 0x80) != 0)
111 case TYPE_DIRNUMNUMARRAY:
114 while ((*dp & 0x80) != 0)
117 while ((*dp & 0x80) != 0)
120 while ((*dp & 0x80) != 0)
127 fprintf(stderr, "unknown type in data_skip\n");
132 static unsigned char *
133 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
146 kv->str = (const char *)dp;
147 return dp + strlen(kv->str) + 1;
149 return data_read_id(dp, &kv->id);
151 return data_read_id(dp, &kv->num);
153 return data_read_ideof(dp, &kv->id, &kv->eof);
155 return data_read_id(dp, &kv->id);
156 case TYPE_DIRSTRARRAY:
157 dp = data_read_ideof(dp, &kv->id, &kv->eof);
158 kv->str = (const char *)dp;
159 return dp + strlen(kv->str) + 1;
160 case TYPE_DIRNUMNUMARRAY:
161 dp = data_read_id(dp, &kv->id);
162 dp = data_read_id(dp, &kv->num);
163 return data_read_ideof(dp, &kv->num2, &kv->eof);
169 static unsigned char *
170 forward_to_key(Repodata *data, Id key, Id schemaid, unsigned char *dp)
174 keyp = data->schemadata + data->schemata[schemaid];
175 while ((k = *keyp++) != 0)
179 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
181 dp = data_skip(dp, TYPE_ID); /* skip that offset */
182 dp = data_skip(dp, TYPE_ID); /* skip that length */
185 if (data->keys[k].storage != KEY_STORAGE_INCORE)
187 dp = data_skip(dp, data->keys[k].type);
192 #define BLOB_PAGEBITS 15
193 #define BLOB_PAGESIZE (1 << BLOB_PAGEBITS)
195 static unsigned char *
196 load_page_range(Repodata *data, unsigned int pstart, unsigned int pend)
198 /* Make sure all pages from PSTART to PEND (inclusive) are loaded,
199 and are consecutive. Return a pointer to the mapping of PSTART. */
200 unsigned char buf[BLOB_PAGESIZE];
203 /* Quick check in case all pages are there already and consecutive. */
204 for (i = pstart; i <= pend; i++)
205 if (data->pages[i].mapped_at == -1
207 && data->pages[i].mapped_at
208 != data->pages[i-1].mapped_at + BLOB_PAGESIZE))
211 return data->blob_store + data->pages[pstart].mapped_at;
213 /* Ensure that we can map the numbers of pages we need at all. */
214 if (pend - pstart + 1 > data->ncanmap)
216 unsigned int oldcan = data->ncanmap;
217 data->ncanmap = pend - pstart + 1;
218 if (data->ncanmap < 4)
220 data->mapped = sat_realloc2(data->mapped, data->ncanmap, sizeof(data->mapped[0]));
221 memset (data->mapped + oldcan, 0, (data->ncanmap - oldcan) * sizeof (data->mapped[0]));
222 data->blob_store = sat_realloc2(data->blob_store, data->ncanmap, BLOB_PAGESIZE);
224 fprintf (stderr, "PAGE: can map %d pages\n", data->ncanmap);
228 /* Now search for "cheap" space in our store. Space is cheap if it's either
229 free (very cheap) or contains pages we search for anyway. */
231 /* Setup cost array. */
232 unsigned int cost[data->ncanmap];
233 for (i = 0; i < data->ncanmap; i++)
235 unsigned int pnum = data->mapped[i];
241 Attrblobpage *p = data->pages + pnum;
242 assert (p->mapped_at != -1);
243 if (pnum >= pstart && pnum <= pend)
250 /* And search for cheapest space. */
251 unsigned int best_cost = -1;
252 unsigned int best = 0;
253 unsigned int same_cost = 0;
254 for (i = 0; i + pend - pstart < data->ncanmap; i++)
256 unsigned int c = cost[i];
258 for (j = 0; j < pend - pstart + 1; j++)
261 best_cost = c, best = i;
262 else if (c == best_cost)
264 /* A null cost won't become better. */
268 /* If all places have the same cost we would thrash on slot 0. Avoid
269 this by doing a round-robin strategy in this case. */
270 if (same_cost == data->ncanmap - pend + pstart - 1)
271 best = data->rr_counter++ % (data->ncanmap - pend + pstart);
273 /* So we want to map our pages from [best] to [best+pend-pstart].
274 Use a very simple strategy, which doesn't make the best use of
275 our resources, but works. Throw away all pages in that range
276 (even ours) then copy around ours (in case they were outside the
277 range) or read them in. */
278 for (i = best; i < best + pend - pstart + 1; i++)
280 unsigned int pnum = data->mapped[i];
282 /* If this page is exactly at the right place already,
283 no need to evict it. */
284 && pnum != pstart + i - best)
286 /* Evict this page. */
288 fprintf (stderr, "PAGE: evict page %d from %d\n", pnum, i);
292 data->pages[pnum].mapped_at = -1;
296 /* Everything is free now. Read in the pages we want. */
297 for (i = pstart; i <= pend; i++)
299 Attrblobpage *p = data->pages + i;
300 unsigned int pnum = i - pstart + best;
301 void *dest = data->blob_store + pnum * BLOB_PAGESIZE;
302 if (p->mapped_at != -1)
304 if (p->mapped_at != pnum * BLOB_PAGESIZE)
307 fprintf (stderr, "PAGECOPY: %d to %d\n", i, pnum);
309 /* Still mapped somewhere else, so just copy it from there. */
310 memcpy (dest, data->blob_store + p->mapped_at, BLOB_PAGESIZE);
311 data->mapped[p->mapped_at / BLOB_PAGESIZE] = 0;
316 unsigned int in_len = p->file_size;
317 unsigned int compressed = in_len & 1;
320 fprintf (stderr, "PAGEIN: %d to %d", i, pnum);
322 /* Not mapped, so read in this page. */
323 if (fseek(data->fp, p->file_offset, SEEK_SET) < 0)
325 perror ("mapping fseek");
328 if (fread(compressed ? buf : dest, in_len, 1, data->fp) != 1)
330 perror ("mapping fread");
335 unsigned int out_len;
336 out_len = unchecked_decompress_buf(buf, in_len,
337 dest, BLOB_PAGESIZE);
338 if (out_len != BLOB_PAGESIZE
339 && i < data->num_pages - 1)
341 fprintf (stderr, "can't decompress\n");
345 fprintf (stderr, " (expand %d to %d)", in_len, out_len);
349 fprintf (stderr, "\n");
352 p->mapped_at = pnum * BLOB_PAGESIZE;
353 data->mapped[pnum] = i + 1;
355 return data->blob_store + best * BLOB_PAGESIZE;
358 static unsigned char *
359 make_vertical_available(Repodata *data, Repokey *key, Id off, Id len)
362 if (key->type == TYPE_VOID)
364 if (off >= data->lastverticaloffset)
366 off -= data->lastverticaloffset;
367 if (off + len > data->vincorelen)
369 return data->vincore + off;
373 if (off + len > key->size)
375 /* we now have the offset, go into vertical */
376 off += data->verticaloffset[key - data->keys];
377 dp = load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
379 dp += off % BLOB_PAGESIZE;
383 static inline unsigned char *
384 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
386 unsigned char *dp = *dpp;
390 if (key->storage == KEY_STORAGE_INCORE)
392 /* hmm, this is a bit expensive */
393 *dpp = data_skip(dp, key->type);
396 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
399 dp = data_read_id(dp, &off);
400 dp = data_read_id(dp, &len);
402 return make_vertical_available(data, key, off, len);
408 maybe_load_repodata(Repodata *data)
410 if (data->state == REPODATA_STUB)
412 if (data->loadcallback)
413 data->loadcallback(data);
415 data->state = REPODATA_ERROR;
417 if (data->state == REPODATA_AVAILABLE)
419 data->state = REPODATA_ERROR;
424 repodata_lookup_str(Repodata *data, Id entry, Id keyid)
431 if (!maybe_load_repodata (data))
434 dp = data->incoredata + data->incoreoffset[entry];
435 dp = data_read_id(dp, &schema);
436 /* make sure the schema of this solvable contains the key */
437 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
440 dp = forward_to_key(data, keyid, schema, dp);
441 key = data->keys + keyid;
442 dp = get_data(data, key, &dp);
445 if (key->type == TYPE_STR)
446 return (const char *)dp;
447 if (key->type != TYPE_ID)
449 /* id type, must either use global or local string store*/
450 dp = data_read_id(dp, &id);
452 return data->spool.stringspace + data->spool.strings[id];
453 return id2str(data->repo->pool, id);
457 repodata_lookup_num(Repodata *data, Id entry, Id keyid, unsigned *value)
467 if (!maybe_load_repodata (data))
470 dp = data->incoredata + data->incoreoffset[entry];
471 dp = data_read_id(dp, &schema);
472 /* make sure the schema of this solvable contains the key */
473 for (keyp = data->schemadata + data->schemata[schema]; *keyp != keyid; keyp++)
476 dp = forward_to_key(data, keyid, schema, dp);
477 key = data->keys + keyid;
478 dp = get_data(data, key, &dp);
481 if (key->type == TYPE_NUM
482 || key->type == TYPE_U32
483 || key->type == TYPE_CONSTANT)
485 dp = data_fetch(dp, &kv, key);
493 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
497 Id k, keyid, *kp, *keyp;
498 unsigned char *dp, *ddp;
503 if (!maybe_load_repodata (data))
506 dp = data->incoredata + data->incoreoffset[entry];
507 dp = data_read_id(dp, &schema);
508 keyp = data->schemadata + data->schemata[schema];
511 /* search in a specific key */
512 for (kp = keyp; (k = *kp++) != 0; )
513 if (data->keys[k].name == keyname)
517 dp = forward_to_key(data, k, schema, dp);
523 while ((keyid = *keyp++) != 0)
526 key = data->keys + keyid;
527 ddp = get_data(data, key, &dp);
530 ddp = data_fetch(ddp, &kv, key);
533 stop = callback(cbdata, data->repo->pool->solvables + data->start + entry, data, key, &kv);
535 while (!kv.eof && !stop);
536 if (onekey || stop > SEARCH_NEXT_KEY)
542 /* extend repodata so that it includes solvables p */
544 repodata_extend(Repodata *data, Id p)
546 if (data->start == data->end)
547 data->start = data->end = p;
550 int old = data->end - data->start;
551 int new = p - data->end + 1;
554 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
555 memset(data->attrs + old, 0, new * sizeof(Id *));
557 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
558 memset(data->incoreoffset + old, 0, new * sizeof(Id));
563 int old = data->end - data->start;
564 int new = data->start - p;
567 data->attrs = sat_realloc2(data->attrs, old + new, sizeof(Id *));
568 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
569 memset(data->attrs, 0, new * sizeof(Id *));
571 data->incoreoffset = sat_realloc2(data->incoreoffset, old + new, sizeof(Id));
572 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
573 memset(data->incoreoffset, 0, new * sizeof(Id));
579 repodata_insert_keyid(Repodata *data, Id entry, Id keyid, Id val, int overwrite)
584 data->attrs = sat_calloc(data->end - data->start + 1, sizeof(Id *));
586 if (data->attrs[entry])
588 for (pp = data->attrs[entry]; *pp; pp += 2)
589 /* Determine equality based on the name only, allows us to change
590 type (when overwrite is set), and makes TYPE_CONSTANT work. */
591 if (data->keys[*pp].name == data->keys[keyid].name)
602 i = pp - data->attrs[entry];
604 data->attrs[entry] = sat_realloc2(data->attrs[entry], i + 3, sizeof(Id));
605 pp = data->attrs[entry] + i;
612 repodata_set(Repodata *data, Id entry, Repokey *key, Id val)
616 /* find key in keys */
617 for (keyid = 1; keyid < data->nkeys; keyid++)
618 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
620 if (key->type == TYPE_CONSTANT && key->size != data->keys[keyid].size)
624 if (keyid == data->nkeys)
626 /* allocate new key */
627 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
628 data->keys[data->nkeys++] = *key;
629 if (data->verticaloffset)
631 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
632 data->verticaloffset[data->nkeys - 1] = 0;
635 repodata_insert_keyid(data, entry, keyid, val, 1);
639 repodata_set_id(Repodata *data, Id entry, Id keyname, Id id)
645 key.storage = KEY_STORAGE_INCORE;
646 repodata_set(data, entry, &key, id);
650 repodata_set_num(Repodata *data, Id entry, Id keyname, Id num)
656 key.storage = KEY_STORAGE_INCORE;
657 repodata_set(data, entry, &key, num);
661 repodata_set_poolstr(Repodata *data, Id entry, Id keyname, const char *str)
666 id = stringpool_str2id(&data->spool, str, 1);
668 id = str2id(data->repo->pool, str, 1);
672 key.storage = KEY_STORAGE_INCORE;
673 repodata_set(data, entry, &key, id);
677 repodata_set_constant(Repodata *data, Id entry, Id keyname, Id constant)
681 key.type = TYPE_CONSTANT;
683 key.storage = KEY_STORAGE_INCORE;
684 repodata_set(data, entry, &key, 0);
688 repodata_set_void(Repodata *data, Id entry, Id keyname)
692 key.type = TYPE_VOID;
694 key.storage = KEY_STORAGE_INCORE;
695 repodata_set(data, entry, &key, 0);
699 repodata_set_str(Repodata *data, Id entry, Id keyname, const char *str)
708 key.storage = KEY_STORAGE_INCORE;
709 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
710 memcpy(data->attrdata + data->attrdatalen, str, l);
711 repodata_set(data, entry, &key, data->attrdatalen);
712 data->attrdatalen += l;
716 repodata_add_dirnumnum(Repodata *data, Id entry, Id keyname, Id dir, Id num, Id num2)
722 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", entry, dir, num, num2, data->attriddatalen);
724 if (data->attrs && data->attrs[entry])
726 for (pp = data->attrs[entry]; *pp; pp += 2)
727 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRNUMNUMARRAY)
732 for (ida = data->attriddata + pp[1]; *ida; ida += 3)
734 if (ida + 1 == data->attriddata + data->attriddatalen)
736 /* this was the last entry, just append it */
737 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
738 data->attriddatalen--; /* overwrite terminating 0 */
742 /* too bad. move to back. */
743 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 4, sizeof(Id));
744 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
745 pp[1] = data->attriddatalen;
746 data->attriddatalen += oldsize;
748 data->attriddata[data->attriddatalen++] = dir;
749 data->attriddata[data->attriddatalen++] = num;
750 data->attriddata[data->attriddatalen++] = num2;
751 data->attriddata[data->attriddatalen++] = 0;
756 key.type = TYPE_DIRNUMNUMARRAY;
758 key.storage = KEY_STORAGE_INCORE;
759 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 4, sizeof(Id));
760 repodata_set(data, entry, &key, data->attriddatalen);
761 data->attriddata[data->attriddatalen++] = dir;
762 data->attriddata[data->attriddatalen++] = num;
763 data->attriddata[data->attriddatalen++] = num2;
764 data->attriddata[data->attriddatalen++] = 0;
768 repodata_add_dirstr(Repodata *data, Id entry, Id keyname, Id dir, const char *str)
770 Id *ida, *pp, stroff;
775 data->attrdata = sat_realloc(data->attrdata, data->attrdatalen + l);
776 memcpy(data->attrdata + data->attrdatalen, str, l);
777 stroff = data->attrdatalen;
778 data->attrdatalen += l;
781 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", entry, dir, str, data->attriddatalen);
783 if (data->attrs && data->attrs[entry])
785 for (pp = data->attrs[entry]; *pp; pp += 2)
786 if (data->keys[*pp].name == keyname && data->keys[*pp].type == TYPE_DIRSTRARRAY)
791 for (ida = data->attriddata + pp[1]; *ida; ida += 2)
793 if (ida + 1 == data->attriddata + data->attriddatalen)
795 /* this was the last entry, just append it */
796 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 2, sizeof(Id));
797 data->attriddatalen--; /* overwrite terminating 0 */
801 /* too bad. move to back. */
802 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + oldsize + 3, sizeof(Id));
803 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
804 pp[1] = data->attriddatalen;
805 data->attriddatalen += oldsize;
807 data->attriddata[data->attriddatalen++] = dir;
808 data->attriddata[data->attriddatalen++] = stroff;
809 data->attriddata[data->attriddatalen++] = 0;
814 key.type = TYPE_DIRSTRARRAY;
816 key.storage = KEY_STORAGE_INCORE;
817 data->attriddata = sat_realloc2(data->attriddata, data->attriddatalen + 3, sizeof(Id));
818 repodata_set(data, entry, &key, data->attriddatalen);
819 data->attriddata[data->attriddatalen++] = dir;
820 data->attriddata[data->attriddatalen++] = stroff;
821 data->attriddata[data->attriddatalen++] = 0;
825 repodata_merge_attrs (Repodata *data, Id dest, Id src)
828 for (keyp = data->attrs[src]; *keyp; keyp += 2)
829 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
832 /*********************************/
834 /* unify with repo_write! */
836 #define EXTDATA_BLOCK 1023
837 #define SCHEMATA_BLOCK 31
838 #define SCHEMATADATA_BLOCK 255
846 data_addid(struct extdata *xd, Id x)
849 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
850 dp = xd->buf + xd->len;
855 *dp++ = (x >> 28) | 128;
857 *dp++ = (x >> 21) | 128;
858 *dp++ = (x >> 14) | 128;
861 *dp++ = (x >> 7) | 128;
863 xd->len = dp - xd->buf;
867 data_addideof(struct extdata *xd, Id x, int eof)
870 x = (x & 63) | ((x & ~63) << 1);
871 data_addid(xd, (eof ? x: x | 64));
875 data_addblob(struct extdata *xd, unsigned char *blob, int len)
877 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
878 memcpy(xd->buf + xd->len, blob, len);
882 /*********************************/
885 addschema_prepare(Repodata *data, Id *schematacache)
890 memset(schematacache, 0, 256 * sizeof(Id));
891 for (i = 0; i < data->nschemata; i++)
893 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
896 schematacache[h] = i + 1;
898 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
899 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
903 addschema(Repodata *data, Id *schema, Id *schematacache)
908 for (sp = schema, len = 0, h = 0; *sp; len++)
913 cid = schematacache[h];
917 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
920 for (cid = 0; cid < data->nschemata; cid++)
921 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
924 /* a new one. make room. */
925 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
926 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
928 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
929 data->schemata[data->nschemata] = data->schemadatalen;
930 data->schemadatalen += len;
931 schematacache[h] = data->nschemata + 1;
933 fprintf(stderr, "addschema: new schema\n");
935 return data->nschemata++;
940 repodata_internalize(Repodata *data)
943 Id id, entry, nentry, *ida;
944 Id schematacache[256];
945 Id schemaid, *schema, *sp, oldschema, *keyp, *seen;
946 unsigned char *dp, *ndp;
947 int newschema, oldcount;
948 struct extdata newincore;
949 struct extdata newvincore;
954 newvincore.buf = data->vincore;
955 newvincore.len = data->vincorelen;
957 schema = sat_malloc2(data->nkeys, sizeof(Id));
958 seen = sat_malloc2(data->nkeys, sizeof(Id));
960 /* Merge the data already existing (in data->schemata, ->incoredata and
961 friends) with the new attributes in data->attrs[]. */
962 nentry = data->end - data->start;
963 addschema_prepare(data, schematacache);
964 memset(&newincore, 0, sizeof(newincore));
965 for (entry = 0; entry < nentry; entry++)
967 memset(seen, 0, data->nkeys * sizeof(Id));
969 dp = data->incoredata + data->incoreoffset[entry];
970 if (data->incoredata)
971 dp = data_read_id(dp, &oldschema);
975 fprintf(stderr, "oldschema %d\n", oldschema);
976 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
977 fprintf(stderr, "schemadata %p\n", data->schemadata);
979 /* seen: -1: old data 0: skipped >0: id + 1 */
982 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
986 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
993 if (data->attrs[entry])
994 for (keyp = data->attrs[entry]; *keyp; keyp += 2)
1001 seen[*keyp] = keyp[1] + 1;
1005 /* Ideally we'd like to sort the new schema here, to ensure
1006 schema equality independend of the ordering. We can't do that
1007 yet. For once see below (old ids need to come before new ids).
1008 An additional difficulty is that we also need to move
1009 the values with the keys. */
1010 schemaid = addschema(data, schema, schematacache);
1012 schemaid = oldschema;
1015 /* Now create data blob. We walk through the (possibly new) schema
1016 and either copy over old data, or insert the new. */
1017 /* XXX Here we rely on the fact that the (new) schema has the form
1018 o1 o2 o3 o4 ... | n1 n2 n3 ...
1019 (oX being the old keyids (possibly overwritten), and nX being
1020 the new keyids). This rules out sorting the keyids in order
1021 to ensure a small schema count. */
1022 data->incoreoffset[entry] = newincore.len;
1023 data_addid(&newincore, schemaid);
1024 for (keyp = data->schemadata + data->schemata[schemaid]; *keyp; keyp++)
1026 key = data->keys + *keyp;
1030 /* Skip the data associated with this old key. */
1031 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1033 ndp = data_skip(dp, TYPE_ID);
1034 ndp = data_skip(ndp, TYPE_ID);
1036 else if (key->storage == KEY_STORAGE_INCORE)
1037 ndp = data_skip(dp, key->type);
1040 if (seen[*keyp] == -1)
1042 /* If this key was an old one _and_ was not overwritten with
1043 a different value copy over the old value (we skipped it
1046 data_addblob(&newincore, dp, ndp - dp);
1049 else if (seen[*keyp])
1051 /* Otherwise we have a new value. Parse it into the internal
1054 unsigned int oldvincorelen = 0;
1057 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1060 oldvincorelen = xd->len;
1062 id = seen[*keyp] - 1;
1069 data_addblob(xd, data->attrdata + id, strlen((char *)(data->attrdata + id)) + 1);
1076 case TYPE_DIRNUMNUMARRAY:
1077 for (ida = data->attriddata + id; *ida; ida += 3)
1079 data_addid(xd, ida[0]);
1080 data_addid(xd, ida[1]);
1081 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
1084 case TYPE_DIRSTRARRAY:
1085 for (ida = data->attriddata + id; *ida; ida += 2)
1087 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
1088 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
1092 fprintf(stderr, "don't know how to handle type %d\n", key->type);
1095 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1097 /* put offset/len in incore */
1098 data_addid(&newincore, data->lastverticaloffset + oldvincorelen);
1099 oldvincorelen = xd->len - oldvincorelen;
1100 data_addid(&newincore, oldvincorelen);
1106 data->incoredata = newincore.buf;
1107 data->incoredatalen = newincore.len;
1108 data->incoredatafree = 0;
1110 data->vincore = newvincore.buf;
1111 data->vincorelen = newvincore.len;
1113 data->attrs = sat_free(data->attrs);
1114 data->attrdata = sat_free(data->attrdata);
1115 data->attrdatalen = 0;
1119 repodata_str2dir(Repodata *data, const char *dir, int create)
1125 while (*dir == '/' && dir[1] == '/')
1129 dire = strchrnul(dir, '/');
1130 if (data->localpool)
1131 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
1133 id = strn2id(data->repo->pool, dir, dire - dir, create);
1136 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
1149 repodata_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max)
1151 return compress_buf(page, len, cpage, max);
1154 #define SOLV_ERROR_EOF 3
1156 static inline unsigned int
1162 for (i = 0; i < 4; i++)
1172 /* Try to either setup on-demand paging (using FP as backing
1173 file), or in case that doesn't work (FP not seekable) slurps in
1174 all pages and deactivates paging. */
1177 repodata_read_or_setup_pages(Repodata *data, unsigned int pagesz, unsigned int blobsz)
1179 FILE *fp = data->fp;
1180 unsigned int npages;
1182 unsigned int can_seek;
1184 unsigned char buf[BLOB_PAGESIZE];
1185 if (pagesz != BLOB_PAGESIZE)
1187 /* We could handle this by slurping in everything. */
1188 fprintf (stderr, "non matching page size\n");
1192 if ((cur_file_ofs = ftell(fp)) < 0)
1196 fprintf (stderr, "can %sseek\n", can_seek ? "" : "NOT ");
1198 npages = (blobsz + BLOB_PAGESIZE - 1) / BLOB_PAGESIZE;
1200 data->num_pages = npages;
1201 data->pages = sat_malloc2(npages, sizeof(data->pages[0]));
1203 /* If we can't seek on our input we have to slurp in everything. */
1205 data->blob_store = sat_malloc(npages * BLOB_PAGESIZE);
1206 for (i = 0; i < npages; i++)
1208 unsigned int in_len = read_u32(fp);
1209 unsigned int compressed = in_len & 1;
1210 Attrblobpage *p = data->pages + i;
1213 fprintf (stderr, "page %d: len %d (%scompressed)\n",
1214 i, in_len, compressed ? "" : "not ");
1220 p->file_offset = cur_file_ofs;
1221 p->file_size = in_len * 2 + compressed;
1222 if (fseek(fp, in_len, SEEK_CUR) < 0)
1225 fprintf (stderr, "can't seek after we thought we can\n");
1226 /* We can't fall back to non-seeking behaviour as we already
1227 read over some data pages without storing them away. */
1230 cur_file_ofs += in_len;
1234 unsigned int out_len;
1235 void *dest = data->blob_store + i * BLOB_PAGESIZE;
1236 p->mapped_at = i * BLOB_PAGESIZE;
1239 /* We can't seek, so suck everything in. */
1240 if (fread(compressed ? buf : dest, in_len, 1, fp) != 1)
1247 out_len = unchecked_decompress_buf(buf, in_len, dest, BLOB_PAGESIZE);
1248 if (out_len != BLOB_PAGESIZE
1251 fprintf (stderr, "can't decompress\n");
1260 /* If we are here we were able to seek to all page
1261 positions, so activate paging by copying FP into our structure.
1262 We dup() the file, so that our callers can fclose() it and we
1263 still have it open. But this means that we share file positions
1264 with the input filedesc. So in case our caller reads it after us,
1265 and calls back into us we might change the file position unexpectedly
1267 int fd = dup (fileno (fp));
1270 /* Jeez! What a bloody system, we can't dup() anymore. */
1274 /* XXX we don't close this yet anywhere. */
1275 data->fp = fdopen (fd, "r");
1278 /* My God! What happened now? */