[Meta]
-Wants=postfix.socket
+Names=multiuser.milestone
+Wants=postfix.socket syslog.socket
Description=Default Milestone
if (!h)
return;
- while (h->iterate_list_head)
- remove_entry(h, h->iterate_list_head);
+ hashmap_clear(h);
free(h);
}
+void hashmap_clear(Hashmap *h) {
+ if (!h)
+ return;
+
+ while (h->iterate_list_head)
+ remove_entry(h, h->iterate_list_head);
+}
+
static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);
void *hashmap_iterate(Hashmap *h, void **state, const void **key);
void *hashmap_iterate_backwards(Hashmap *h, void **state, const void **key);
+void hashmap_clear(Hashmap *h);
void *hashmap_steal_first(Hashmap *h);
void* hashmap_first(Hashmap *h);
void* hashmap_last(Hashmap *h);
#define HASHMAP_FOREACH(e, h, state) \
for ((state) = NULL, (e) = hashmap_iterate((h), &(state), NULL); (e); (e) = hashmap_iterate((h), &(state), NULL))
+#define HASHMAP_FOREACH_KEY(e, k, h, state) \
+ for ((state) = NULL, (e) = hashmap_iterate((h), &(state), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(state), (const void**) &(k)))
+
#define HASHMAP_FOREACH_BACKWARDS(e, h, state) \
for ((state) = NULL, (e) = hashmap_iterate_backwards((h), &(state), NULL); (e); (e) = hashmap_iterate_backwards((h), &(state), NULL))
return j;
}
-int job_link(Job *j) {
- int r;
-
- assert(j);
- assert(!j->linked);
-
- if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0)
- return r;
-
- j->name->meta.job = j;
-
- j->linked = true;
-
- return 0;
-}
-
void job_free(Job *j) {
assert(j);
/* Detach from next 'bigger' objects */
if (j->linked) {
- assert(j->name);
- assert(j->name->meta.job == j);
- j->name->meta.job = NULL;
+ if (j->name->meta.job == j)
+ j->name->meta.job = NULL;
hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
}
assert(j);
assert(f);
- fprintf(f, "Job %u (%s) →%s in state %s\n",
+ fprintf(f, "Job %u (%s) → %s in state %s\n",
j->id,
name_id(j->name),
job_type_table[j->type],
};
Job* job_new(Manager *m, JobType type, Name *name);
-int job_link(Job *job);
void job_free(Job *job);
void job_dump(Job *j, FILE*f);
free(t);
return r;
}
+
+ t = NULL;
}
free(t);
goto finish;
}
- manager_dump_names(m, stdout);
- /* if ((r = manager_add_job(m, JOB_START, milestone, JOB_REPLACE, &job)) < 0) { */
- /* fprintf(stderr, "Failed to start default milestone: %s\n", strerror(-r)); */
- /* goto finish; */
- /* } */
+ if ((r = manager_add_job(m, JOB_START, milestone, JOB_REPLACE, &job)) < 0) {
+ fprintf(stderr, "Failed to start default milestone: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ manager_dump_names(m, stdout);
retval = 0;
free(m);
}
+static void transaction_abort(Manager *m) {
+ Job *j;
+
+ assert(m);
+ assert(m->n_dependency_depth == 0);
+
+ while ((j = hashmap_steal_first(m->jobs_to_add)))
+ job_free(j);
+
+ set_clear(m->jobs_to_remove);
+}
+
+static int transaction_activate(Manager *m) {
+ Job *j;
+ int r;
+ void *state;
+
+ assert(m);
+ assert(m->n_dependency_depth == 0);
+
+ /* This applies the changes recorded in jobs_to_add and
+ * jobs_to_remove to the actual list of jobs */
+
+ HASHMAP_FOREACH(j, m->jobs_to_add, state) {
+ assert(!j->linked);
+
+ if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0)
+ goto rollback;
+ }
+
+ /* all entries are now registered, now make sure the names
+ * know about that. */
+
+ while ((j = hashmap_steal_first(m->jobs_to_add))) {
+ j->name->meta.job = j;
+ j->linked = true;
+ }
+
+ while ((j = set_steal_first(m->jobs_to_remove)))
+ job_free(j);
+
+ return 0;
+
+rollback:
+
+ HASHMAP_FOREACH(j, m->jobs_to_add, state)
+ hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
+
+ transaction_abort(m);
+ return r;
+}
+
int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_ret) {
Job *ret, *other;
void *state;
assert(type < _JOB_TYPE_MAX);
assert(name);
assert(mode < _JOB_MODE_MAX);
- assert(_ret);
/* Check for conflicts, first against the jobs we shall
* create */
if (!(ret = job_new(m, type, name)))
return -ENOMEM;
+ m->n_dependency_depth ++;
+
if ((r = hashmap_put(m->jobs_to_add, name, ret)) < 0)
goto fail;
goto fail;
}
+ if (--m->n_dependency_depth <= 0)
+ if ((r = transaction_activate(m)) < 0) {
+ transaction_abort(m);
+ return r;
+ }
+
+
if (_ret)
*_ret = ret;
fail:
job_free(ret);
+ if (--m->n_dependency_depth <= 0)
+ transaction_abort(m);
+
return r;
}
if ((r = name_load_dropin(name)) < 0)
return r;
+ if ((r = name_link_names(name)) < 0)
+ return r;
+
name->meta.state = NAME_LOADED;
return 0;
}
void manager_dump_names(Manager *s, FILE *f) {
void *state;
Name *n;
+ const char *t;
assert(s);
assert(f);
- HASHMAP_FOREACH(n, s->names, state)
- name_dump(n, f);
+ HASHMAP_FOREACH_KEY(n, t, s->names, state)
+ if (name_id(n) == t)
+ name_dump(n, f);
}
Set *jobs_to_remove;
bool dispatching_load_queue:1;
+
+ unsigned n_dependency_depth;
};
Manager* manager_new(void);
return n;
}
+int name_link_names(Name *n) {
+ char *t;
+ void *state;
+ int r;
+
+ assert(n);
+
+ if (!n->meta.linked)
+ return 0;
+
+ /* Link all names that aren't linked yet */
+
+ SET_FOREACH(t, n->meta.names, state)
+ if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0) {
+
+ if (r == -EEXIST && hashmap_get(n->meta.manager->names, t) == n)
+ continue;
+
+ return r;
+ }
+
+ return 0;
+}
+
int name_link(Name *n) {
- char **t;
int r;
- void *state;
assert(n);
assert(!set_isempty(n->meta.names));
assert(!n->meta.linked);
- SET_FOREACH(t, n->meta.names, state)
- if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0)
- goto fail;
+ n->meta.linked = true;
- if (n->meta.state == NAME_STUB)
- LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
+ if ((r = name_link_names(n) < 0)) {
+ char *t;
+ void *state;
- n->meta.linked = true;
+ /* Rollback the registered names */
+ SET_FOREACH(t, n->meta.names, state)
+ hashmap_remove(n->meta.manager->names, t);
- return 0;
+ n->meta.linked = false;
+ return r;
+ }
-fail:
- SET_FOREACH(t, n->meta.names, state)
- assert_se(hashmap_remove(n->meta.manager->names, t) == n);
+ if (n->meta.state == NAME_STUB)
+ LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
- return r;
+ return 0;
}
static void bidi_set_free(Name *name, Set *s) {
/* Detach from next 'bigger' objects */
if (name->meta.linked) {
- char **t;
+ char *t;
void *state;
SET_FOREACH(t, name->meta.names, state)
if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
return r;
+ if (name->meta.linked)
+ if ((r = name_link_names(name)) < 0)
+ return r;
+
return 0;
}
[SOCKET_MAINTAINANCE] = "maintainance"
};
+ void *state;
+ char *t;
+
assert(n);
- fprintf(stderr,
- "Name %s (\"%s\") in state %s\n",
+ fprintf(f,
+ "Name %s\n"
+ "\tDescription: %s\n"
+ "\tState: %s\n",
name_id(n),
n->meta.description ? n->meta.description : name_id(n),
state_table[n->meta.state]);
+ fprintf(f, "\tNames: ");
+ SET_FOREACH(t, n->meta.names, state)
+ fprintf(f, "%s ", t);
+ fprintf(f, "\n");
+
switch (n->meta.type) {
case NAME_SOCKET: {
int r;
else
t = s;
- fprintf(stderr, "\t%s in state %s\n", t, socket_state_table[n->socket.state]);
+ fprintf(f, "\t%s in state %s\n", t, socket_state_table[n->socket.state]);
free(s);
break;
}
}
if (n->meta.job) {
- fprintf(f, "\t▶ ");
+ fprintf(f, "\t");
job_dump(n->meta.job, f);
}
}
Name *name_new(Manager *m);
void name_free(Name *name);
int name_link(Name *name);
+int name_link_names(Name *name);
int name_merge(Name *name, Name *other);
int name_augment(Name *n);
const char* name_id(Name *n);
[Meta]
-Description=Postfix Listening Socket
+Description=Postfix SMTP Socket
[Socket]
Listen=25
Set* set_copy(Set *s) {
return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s)));
}
+
+void set_clear(Set *s) {
+ hashmap_clear(MAKE_HASHMAP(s));
+}
void *set_iterate(Set *s, void **state);
void *set_iterate_backwards(Set *s, void **state);
+void set_clear(Set *s);
void *set_steal_first(Set *s);
void* set_first(Set *s);
void* set_last(Set *s);
+[Meta]
+Description=Syslog Socket
+
[Socket]
Listen=/dev/log
+Type=dgram