repo_appdata.h)
ENDIF (ENABLE_APPDATA)
+IF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+ SET (libsolvext_SRCS ${libsolvext_SRCS}
+ repodata_diskusage.c)
+ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO)
+
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
IF (HAVE_LINKER_VERSION_SCRIPT)
SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
#ifdef ENABLE_COMPLEX_DEPS
#include "pool_parserpmrichdep.h"
#endif
+#include "repodata_diskusage.h"
enum state {
STATE_START,
Id chksumtype;
Id handle;
XML_Parser *parser;
- Id (*dirs)[3]; /* dirid, size, nfiles */
- int ndirs;
+ Queue diskusageq;
const char *language; /* default language */
Id langcache[ID_NUM_INTERNAL]; /* cache for the default language */
return pd->langcache[tag];
}
-static int
-id3_cmp (const void *v1, const void *v2, void *dp)
-{
- Id *i1 = (Id*)v1;
- Id *i2 = (Id*)v2;
- return i1[0] - i2[0];
-}
-
-static void
-commit_diskusage (struct parsedata *pd, Id handle)
-{
- int i;
- Dirpool *dp = &pd->data->dirpool;
- /* Now sort in dirid order. This ensures that parents come before
- their children. */
- if (pd->ndirs > 1)
- solv_sort(pd->dirs, pd->ndirs, sizeof (pd->dirs[0]), id3_cmp, 0);
- /* Substract leaf numbers from all parents to make the numbers
- non-cumulative. This must be done post-order (i.e. all leafs
- adjusted before parents). We ensure this by starting at the end of
- the array moving to the start, hence seeing leafs before parents. */
- for (i = pd->ndirs; i--;)
- {
- Id p = dirpool_parent(dp, pd->dirs[i][0]);
- int j = i;
- for (; p; p = dirpool_parent(dp, p))
- {
- for (; j--;)
- if (pd->dirs[j][0] == p)
- break;
- if (j >= 0)
- {
- if (pd->dirs[j][1] < pd->dirs[i][1])
- pd->dirs[j][1] = 0;
- else
- pd->dirs[j][1] -= pd->dirs[i][1];
- if (pd->dirs[j][2] < pd->dirs[i][2])
- pd->dirs[j][2] = 0;
- else
- pd->dirs[j][2] -= pd->dirs[i][2];
- }
- else
- /* Haven't found this parent in the list, look further if
- we maybe find the parents parent. */
- j = i;
- }
- }
-#if 0
- char sbuf[1024];
- char *buf = sbuf;
- unsigned slen = sizeof (sbuf);
- for (i = 0; i < pd->ndirs; i++)
- {
- dir2str (attr, pd->dirs[i][0], &buf, &slen);
- fprintf (stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
- }
- if (buf != sbuf)
- free (buf);
-#endif
- for (i = 0; i < pd->ndirs; i++)
- if (pd->dirs[i][1] || pd->dirs[i][2])
- {
- repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
- }
- pd->ndirs = 0;
-}
-
-
/*
* makeevr_atts
* parse 'epoch', 'ver' and 'rel', return evr Id
case STATE_DIR:
{
long filesz = 0, filenum = 0;
- Id dirid;
+ Id did;
+
if ((str = find_attr("name", atts)) == 0)
{
pd->ret = pool_error(pool, -1, "<dir .../> tag without 'name' attribute");
str = pd->content;
}
}
- dirid = repodata_str2dir(pd->data, str, 1);
+ did = repodata_str2dir(pd->data, str, 1);
if ((str = find_attr("size", atts)) != 0)
filesz = strtol(str, 0, 0);
if ((str = find_attr("count", atts)) != 0)
filenum = strtol(str, 0, 0);
- pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
- pd->dirs[pd->ndirs][0] = dirid;
- pd->dirs[pd->ndirs][1] = filesz;
- pd->dirs[pd->ndirs][2] = filenum;
- pd->ndirs++;
+ if (filesz || filenum)
+ {
+ queue_push(&pd->diskusageq, did);
+ queue_push2(&pd->diskusageq, filesz, filenum);
+ }
break;
}
case STATE_CHANGELOG:
repodata_add_poolstr_array(pd->data, handle, SOLVABLE_KEYWORDS, pd->content);
break;
case STATE_DISKUSAGE:
- if (pd->ndirs)
- commit_diskusage(pd, handle);
+ if (pd->diskusageq.count)
+ repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
break;
case STATE_ORDER:
if (pd->content[0])
pd.lcontent = 0;
pd.kind = 0;
pd.language = language && *language && strcmp(language, "en") != 0 ? language : 0;
+ queue_init(&pd.diskusageq);
init_cshash(&pd);
if ((flags & REPO_EXTEND_SOLVABLES) != 0)
join_freemem(&pd.jd);
free_cshash(&pd);
repodata_free_dircache(data);
+ queue_free(&pd.diskusageq);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
#ifdef ENABLE_COMPLEX_DEPS
#include "pool_parserpmrichdep.h"
#endif
+#include "repodata_diskusage.h"
struct datashare {
Id name;
int last_found_source;
struct datashare *share_with;
int nshare;
- Id (*dirs)[3]; /* dirid, size, nfiles */
- int ndirs;
+ Queue diskusageq;
struct joindata jd;
char *language; /* the default language */
Id langcache[ID_NUM_INTERNAL]; /* cache for the default language */
repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch);
}
-/*
- * add_dirline
- * add a line with directory information
- *
- */
-
-static void
-add_dirline(struct parsedata *pd, char *line)
-{
- char *sp[6];
- long filesz;
- long filenum;
- Id dirid;
- if (split(line, sp, 6) != 5)
- return;
- pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
- filesz = strtol(sp[1], 0, 0);
- filesz += strtol(sp[2], 0, 0);
- filenum = strtol(sp[3], 0, 0);
- filenum += strtol(sp[4], 0, 0);
- /* hack: we know that there's room for a / */
- if (*sp[0] != '/')
- *--sp[0] = '/';
- dirid = repodata_str2dir(pd->data, sp[0], 1);
-#if 0
-fprintf(stderr, "%s -> %d\n", sp[0], dirid);
-#endif
- pd->dirs[pd->ndirs][0] = dirid;
- pd->dirs[pd->ndirs][1] = filesz;
- pd->dirs[pd->ndirs][2] = filenum;
- pd->ndirs++;
-}
-
static void
set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *line)
{
}
-/*
- * id3_cmp
- * compare
- *
- */
-
-static int
-id3_cmp(const void *v1, const void *v2, void *dp)
-{
- Id *i1 = (Id*)v1;
- Id *i2 = (Id*)v2;
- return i1[0] - i2[0];
-}
-
-
-/*
- * commit_diskusage
- *
- */
-
-static void
-commit_diskusage(struct parsedata *pd, Id handle)
-{
- int i;
- Dirpool *dp = &pd->data->dirpool;
- /* Now sort in dirid order. This ensures that parents come before
- their children. */
- if (pd->ndirs > 1)
- solv_sort(pd->dirs, pd->ndirs, sizeof(pd->dirs[0]), id3_cmp, 0);
- /* Substract leaf numbers from all parents to make the numbers
- non-cumulative. This must be done post-order (i.e. all leafs
- adjusted before parents). We ensure this by starting at the end of
- the array moving to the start, hence seeing leafs before parents. */
- for (i = pd->ndirs; i--;)
- {
- Id p = dirpool_parent(dp, pd->dirs[i][0]);
- int j = i;
- for (; p; p = dirpool_parent(dp, p))
- {
- for (; j--;)
- if (pd->dirs[j][0] == p)
- break;
- if (j >= 0)
- {
- if (pd->dirs[j][1] < pd->dirs[i][1])
- pd->dirs[j][1] = 0;
- else
- pd->dirs[j][1] -= pd->dirs[i][1];
- if (pd->dirs[j][2] < pd->dirs[i][2])
- pd->dirs[j][2] = 0;
- else
- pd->dirs[j][2] -= pd->dirs[i][2];
- }
- else
- /* Haven't found this parent in the list, look further if
- we maybe find the parents parent. */
- j = i;
- }
- }
-#if 0
- char sbuf[1024];
- char *buf = sbuf;
- unsigned slen = sizeof(sbuf);
- for (i = 0; i < pd->ndirs; i++)
- {
- dir2str(attr, pd->dirs[i][0], &buf, &slen);
- fprintf(stderr, "have dir %d %d %d %s\n", pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2], buf);
- }
- if (buf != sbuf)
- free (buf);
-#endif
- for (i = 0; i < pd->ndirs; i++)
- if (pd->dirs[i][1] || pd->dirs[i][2])
- {
- repodata_add_dirnumnum(pd->data, handle, SOLVABLE_DISKUSAGE, pd->dirs[i][0], pd->dirs[i][1], pd->dirs[i][2]);
- }
- pd->ndirs = 0;
-}
-
-
/* Unfortunately "a"[0] is no constant expression in the C languages,
so we need to pass the four characters individually :-/ */
#define CTAG(a,b,c,d) ((unsigned)(((unsigned char)a) << 24) \
}
pd->nfilelist = 0;
}
- /* A self provide, except for source packages. This is harmless
+ /* Add self provide, except for source packages. This is harmless
to do twice (in case we see the same package twice). */
if (s->name && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
repo_rewrite_suse_deps(s, freshens);
- if (pd->ndirs)
- commit_diskusage(pd, handle);
+ if (pd->diskusageq.count)
+ repodata_add_diskusage(pd->data, handle, &pd->diskusageq);
}
static Hashtable
int indelta = 0;
int last_found_pack = 0;
Id first_new_pkg = 0;
- char *sp[5];
+ char *sp[6];
struct parsedata pd;
Repodata *data = 0;
Id handle = 0;
pd.data = data;
pd.flags = flags;
pd.language = language && *language ? solv_strdup(language) : 0;
+ queue_init(&pd.diskusageq);
linep = line;
s = 0;
continue;
}
case CTAG('=', 'D', 'i', 'r'):
- add_dirline(&pd, line + 6);
- continue;
+ if (split(line + 6, sp, 6) == 5)
+ {
+ long filesz, filenum;
+ Id did;
+
+ filesz = strtol(sp[1], 0, 0);
+ filesz += strtol(sp[2], 0, 0);
+ filenum = strtol(sp[3], 0, 0);
+ filenum += strtol(sp[4], 0, 0);
+ if (*sp[0] != '/')
+ *--sp[0] = '/'; /* hack: we know that there's room for a / */
+ did = repodata_str2dir(data, sp[0], 1);
+ queue_push(&pd.diskusageq, did);
+ queue_push2(&pd.diskusageq, (Id)filesz, (Id)filenum);
+ }
+ break;
case CTAG('=', 'C', 'a', 't'):
repodata_set_poolstr(data, handle, langtag(&pd, SOLVABLE_CATEGORY, line_lang), line + 3 + keylen);
break;
solv_free(pd.language);
solv_free(line);
join_freemem(&pd.jd);
+ queue_free(&pd.diskusageq);
return pd.ret;
}
--- /dev/null
+/*
+ * repodata_diskusage.c
+ *
+ * Small helper to convert diskusage data from sustags or rpmmd
+ *
+ * Copyright (c) 2017, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "repodata_diskusage.h"
+
+/* The queue contains (dirid, kbytes, inodes) triplets */
+
+static int
+add_diskusage_sortfn(const void *ap, const void *bp, void *dp)
+{
+ return *(Id *)ap - *(Id *)bp;
+}
+
+void
+repodata_add_diskusage(Repodata *data, Id handle, Queue *q)
+{
+ int i, j;
+ Dirpool *dp = &data->dirpool;
+
+ /* Sort in dirid order. This ensures that parents come before
+ * their children. */
+ if (q->count > 3)
+ solv_sort(q->elements, q->count / 3, 3 * sizeof(Id), add_diskusage_sortfn, 0);
+ for (i = 3; i < q->count; i += 3)
+ {
+ /* subtract data from parent */
+ Id did = q->elements[i];
+ if (i + 3 < q->count && q->elements[i + 3] == did)
+ {
+ /* identical directory entry! zero this one */
+ q->elements[i + 1] = 0;
+ q->elements[i + 2] = 0;
+ continue;
+ }
+ while (did)
+ {
+ did = dirpool_parent(dp, did);
+ for (j = i - 3; j >= 0; j -= 3)
+ if (q->elements[j] == did)
+ break;
+ if (j >= 0)
+ {
+ if ((unsigned int)q->elements[j + 1] > (unsigned int)q->elements[i + 1])
+ q->elements[j + 1] -= q->elements[i + 1];
+ else
+ q->elements[j + 1] = 0;
+ if ((unsigned int)q->elements[j + 2] > (unsigned int)q->elements[i + 2])
+ q->elements[j + 2] -= q->elements[i + 2];
+ else
+ q->elements[j + 2] = 0;
+ break;
+ }
+ }
+ }
+ /* now commit data */
+ for (i = 0; i < q->count; i += 3)
+ if (q->elements[i + 1] || q->elements[i + 2])
+ repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, q->elements[i], q->elements[i + 1], q->elements[i + 2]);
+ /* empty queue */
+ queue_empty(q);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+extern void repodata_add_diskusage(Repodata *data, Id handle, Queue *q);
+
+