Skip to content

Commit 6e0ad75

Browse files
committed
librlist: add rlist_copy_core_spec()
Problem: There is no way to copy a set of cores from an rlist, but this would be useful when creating a set of cores to reserve for the OS. Add a new function rlist_copy_core_spec() which can copy cores from an rlist object using a specification of the form: cores[@Ranks] [cores[@Ranks]]... where `cores` and the optional `ranks` are idsets of the cores/ranks to include in the copy.
1 parent dd04ef1 commit 6e0ad75

File tree

3 files changed

+200
-0
lines changed

3 files changed

+200
-0
lines changed

src/common/librlist/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ librlist_la_SOURCES = \
2525
match.c \
2626
rlist.c \
2727
rlist.h \
28+
corespec.c \
2829
rlist_private.h
2930

3031
librlist_hwloc_la_SOURCES = \

src/common/librlist/corespec.c

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/************************************************************\
2+
* Copyright 2025 Lawrence Livermore National Security, LLC
3+
* (c.f. AUTHORS, NOTICE.LLNS, COPYING)
4+
*
5+
* This file is part of the Flux resource manager framework.
6+
* For details, see https://github.com/flux-framework.
7+
*
8+
* SPDX-License-Identifier: LGPL-3.0
9+
\************************************************************/
10+
11+
#if HAVE_CONFIG_H
12+
#include "config.h"
13+
#endif
14+
15+
#include <errno.h>
16+
#include <string.h>
17+
18+
#include <flux/core.h>
19+
#include <flux/idset.h>
20+
21+
#include "src/common/libczmqcontainers/czmq_containers.h"
22+
#include "src/common/libutil/errprintf.h"
23+
24+
#include "rlist.h"
25+
#include "rnode.h"
26+
#include "rlist_private.h"
27+
28+
struct core_spec {
29+
char *spec;
30+
struct idset *cores;
31+
struct idset *ranks;
32+
};
33+
34+
static void core_spec_destroy (struct core_spec *spec)
35+
{
36+
if (spec) {
37+
int saved_errno = errno;
38+
idset_destroy (spec->cores);
39+
idset_destroy (spec->ranks);
40+
free (spec->spec);
41+
free (spec);
42+
errno = saved_errno;
43+
}
44+
}
45+
46+
static struct core_spec *core_spec_create (const char *s, flux_error_t *errp)
47+
{
48+
idset_error_t error;
49+
struct core_spec *spec;
50+
const char *ranks = NULL;
51+
const char *cores;
52+
int len = -1;
53+
54+
cores = s;
55+
if ((ranks = strchr (cores, '@'))) {
56+
len = ranks - cores;
57+
ranks++;
58+
}
59+
if (!(spec = calloc (1, sizeof (*spec)))
60+
|| !(spec->spec = strdup (s))) {
61+
errprintf (errp, "Out of memory");
62+
goto error;
63+
}
64+
if ((ranks && !(spec->ranks = idset_decode_ex (ranks, -1, 0, 0, &error)))
65+
|| !(spec->cores = idset_decode_ex (cores, len, 0, 0, &error))) {
66+
errprintf (errp, "%s", error.text);
67+
goto error;
68+
}
69+
if ((spec->ranks && idset_count (spec->ranks) == 0)
70+
|| idset_count (spec->cores) == 0) {
71+
errprintf (errp, "ranks/cores cannot be empty");
72+
goto error;
73+
}
74+
return spec;
75+
error:
76+
core_spec_destroy (spec);
77+
return NULL;
78+
}
79+
80+
static struct rnode *core_spec_copy (const struct rnode *orig,
81+
struct core_spec *spec)
82+
{
83+
struct rnode *n = NULL;
84+
85+
/* If spec->ranks is NULL, this indicates all ranks
86+
*/
87+
if (!spec->ranks || idset_test (spec->ranks, orig->rank)) {
88+
/* Create new rnode object with just the cores intersection, keeping
89+
* hostname and properties.
90+
*/
91+
struct idset *ids = idset_intersect (orig->cores->ids, spec->cores);
92+
if (ids != NULL
93+
&& idset_count (ids) > 0
94+
&& (n = rnode_create_idset (orig->hostname, orig->rank, ids))) {
95+
n->properties = zhashx_dup (orig->properties);
96+
}
97+
idset_destroy (ids);
98+
}
99+
return n;
100+
}
101+
102+
static void core_spec_destructor (void **item)
103+
{
104+
if (item) {
105+
struct core_spec *spec = *item;
106+
core_spec_destroy (spec);
107+
*item = NULL;
108+
}
109+
}
110+
111+
static zlistx_t *core_spec_list_create (const char *core_spec,
112+
flux_error_t *errp)
113+
{
114+
char *copy;
115+
char *str;
116+
char *spec;
117+
char *sp = NULL;
118+
zlistx_t *l = zlistx_new ();
119+
120+
if (!l || !(copy = strdup (core_spec)))
121+
return NULL;
122+
str = copy;
123+
124+
zlistx_set_destructor (l, core_spec_destructor);
125+
126+
while ((spec = strtok_r (str, " \t", &sp))) {
127+
struct core_spec *cspec;
128+
if (!(cspec = core_spec_create (spec, errp)))
129+
goto error;
130+
if (!zlistx_add_end (l, cspec)) {
131+
errprintf (errp, "Out of memory");
132+
goto error;
133+
}
134+
str = NULL;
135+
}
136+
free (copy);
137+
return l;
138+
error:
139+
free (copy);
140+
zlistx_destroy (&l);
141+
return NULL;
142+
}
143+
144+
struct rlist *rlist_copy_core_spec (const struct rlist *orig,
145+
const char *core_spec,
146+
flux_error_t *errp)
147+
{
148+
struct core_spec *spec;
149+
struct rlist *rl = NULL;
150+
zlistx_t *l;
151+
152+
if (!(l = core_spec_list_create (core_spec, errp)))
153+
return NULL;
154+
155+
spec = zlistx_first (l);
156+
while (spec) {
157+
struct rlist *tmp;
158+
if (!(tmp = rlist_copy_internal (orig,
159+
(rnode_copy_f) core_spec_copy,
160+
(void *) spec))) {
161+
errprintf (errp, "failed to copy spec '%s'", spec->spec);
162+
goto error;
163+
}
164+
if (rl != NULL) {
165+
if (rlist_add (rl, tmp) < 0) {
166+
errprintf (errp,
167+
"rlist_add '%s' failed: %s",
168+
spec->spec,
169+
strerror (errno));
170+
goto error;
171+
}
172+
rlist_destroy (tmp);
173+
}
174+
else
175+
rl = tmp;
176+
spec = zlistx_next (l);
177+
}
178+
zlistx_destroy (&l);
179+
return rl;
180+
error:
181+
rlist_destroy (rl);
182+
zlistx_destroy (&l);
183+
return NULL;
184+
}
185+
186+
/* vi: ts=4 sw=4 expandtab
187+
*/

src/common/librlist/rlist.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,5 +287,17 @@ char *rlist_properties_encode (const struct rlist *rl);
287287

288288
struct rlist *rlist_from_config (json_t *conf, flux_error_t *errp);
289289

290+
/* Create a copy of rlist 'rl' using 'core_spec', which indicates a
291+
* set of cores via the form:
292+
*
293+
* cores[@ranks] [cores[@ranks]]...
294+
*
295+
* Where 'cores' is an idset of cores to copy and the optional 'ranks'
296+
* and idset of ranks from which to copy them. It is not an error to
297+
* specify cores and or ranks that do not exist in the source rlist 'rl'.
298+
*/
299+
struct rlist *rlist_copy_core_spec (const struct rlist *rl,
300+
const char *spec,
301+
flux_error_t *errp);
290302

291303
#endif /* !HAVE_SCHED_RLIST_H */

0 commit comments

Comments
 (0)