@@ -415,6 +415,188 @@ static struct taskmap *taskmap_decode_pmi (const char *s, flux_error_t *errp)
415415 return NULL ;
416416}
417417
418+ struct raw_task {
419+ int taskid ;
420+ int nodeid ;
421+ int repeat ;
422+ };
423+
424+ static void item_destructor (void * * item )
425+ {
426+ if (item ) {
427+ free (* item );
428+ * item = NULL ;
429+ }
430+ }
431+
432+ static int taskid_cmp (const void * a , const void * b )
433+ {
434+ const struct raw_task * t1 = a ;
435+ const struct raw_task * t2 = b ;
436+ return (t1 -> taskid - t2 -> taskid );
437+ }
438+
439+ static int raw_task_append (zlistx_t * l , int taskid , int nodeid , int repeat )
440+ {
441+ struct raw_task * t = calloc (1 , sizeof (* t ));
442+ if (!t )
443+ return -1 ;
444+ t -> taskid = taskid ;
445+ t -> nodeid = nodeid ;
446+ t -> repeat = repeat ;
447+ if (!zlistx_add_end (l , t )) {
448+ free (t );
449+ return -1 ;
450+ }
451+ return 0 ;
452+ }
453+
454+ static zlistx_t * raw_task_list_create (void )
455+ {
456+ zlistx_t * l ;
457+ if (!(l = zlistx_new ())) {
458+ errno = ENOMEM ;
459+ return NULL ;
460+ }
461+ zlistx_set_destructor (l , item_destructor );
462+ zlistx_set_comparator (l , & taskid_cmp );
463+ return l ;
464+ }
465+
466+ static int raw_task_list_append (zlistx_t * l ,
467+ const char * s ,
468+ int nodeid ,
469+ flux_error_t * errp )
470+ {
471+ int rc = -1 ;
472+ unsigned int id ;
473+ idset_error_t error ;
474+ struct idset * ids ;
475+
476+ if (!(ids = idset_decode_ex (s , -1 , 0 , IDSET_FLAG_AUTOGROW , & error ))) {
477+ errprintf (errp , "%s" , error .text );
478+ goto error ;
479+ }
480+ id = idset_first (ids );
481+ while (id != IDSET_INVALID_ID ) {
482+ unsigned int next = idset_next (ids , id );
483+ int repeat = 1 ;
484+ while (next == id + repeat ) {
485+ next = idset_next (ids , next );
486+ repeat ++ ;
487+ }
488+ if (raw_task_append (l , id , nodeid , repeat ) < 0 ) {
489+ errprintf (errp , "Out of memory" );
490+ goto error ;
491+ }
492+ id = next ;
493+ }
494+ rc = 0 ;
495+ error :
496+ idset_destroy (ids );
497+ return rc ;
498+ }
499+
500+ static int raw_task_check (struct raw_task * a ,
501+ struct raw_task * b ,
502+ flux_error_t * errp )
503+ {
504+ struct raw_task t_init = { .taskid = -1 , .repeat = 1 };
505+ int start , end1 , end2 , end ;
506+
507+ if (a == NULL )
508+ a = & t_init ;
509+
510+ /* Note: a->taskid <= b->taskid since taskmap_decode_raw() sorts
511+ * raw_task objects.
512+ */
513+ start = b -> taskid ;
514+ end1 = a -> taskid + a -> repeat - 1 ;
515+ end2 = b -> taskid + b -> repeat - 1 ;
516+ end = end1 <= end2 ? end1 : end2 ;
517+
518+ /* If end - start is nonzero then we have overlap. report it.
519+ */
520+ int overlap = end - start ;
521+ if (overlap >= 0 ) {
522+ /* taskid overlap detected, report as error
523+ */
524+ if (overlap == 0 )
525+ errprintf (errp , "duplicate taskid specified: %d" , start );
526+ else
527+ errprintf (errp , "duplicate taskids specified: %d-%d" , start , end );
528+ return -1 ;
529+ }
530+ /* Now check that tasks are consecutive. It is an error if not since
531+ * holes in taskids in a taskmap are not allowed
532+ */
533+ if (overlap != -1 ) {
534+ if (overlap == -2 )
535+ return errprintf (errp , "missing taskid: %d" , end + 1 );
536+ else
537+ return errprintf (errp ,
538+ "missing taskids: %d-%d" ,
539+ end + 1 ,
540+ end - overlap - 1 );
541+ }
542+ return 0 ;
543+ }
544+
545+ static struct taskmap * taskmap_decode_raw (const char * s , flux_error_t * errp )
546+ {
547+ char * tok ;
548+ char * p ;
549+ char * q ;
550+ char * cpy = NULL ;
551+ struct taskmap * map = NULL ;
552+ zlistx_t * l = NULL ;
553+ int nodeid = 0 ;
554+ struct raw_task * t , * prev ;
555+
556+ if (!s || strlen (s ) == 0 ) {
557+ errprintf (errp , "Invalid argument" );
558+ return NULL ;
559+ }
560+ if (!(map = taskmap_create ())
561+ || !(cpy = strdup (s ))
562+ || !(l = raw_task_list_create ())) {
563+ errprintf (errp , "Out of memory" );
564+ goto error ;
565+ }
566+
567+ p = cpy ;
568+
569+ while ((tok = strtok_r (p , ";" , & q ))) {
570+ if (raw_task_list_append (l , tok , nodeid ++ , errp ) < 0 )
571+ goto error ;
572+ p = NULL ;
573+ }
574+
575+ /* sort by taskid */
576+ zlistx_sort (l );
577+ t = zlistx_first (l );
578+ prev = NULL ;
579+
580+ while (t ) {
581+ if (raw_task_check (prev , t , errp ) < 0 )
582+ goto error ;
583+ if (taskmap_append (map , t -> nodeid , 1 , t -> repeat ) < 0 ) {
584+ errprintf (errp , "taskmap_append: %s" , strerror (errno ));
585+ goto error ;
586+ }
587+ prev = t ;
588+ t = zlistx_next (l );
589+ }
590+ zlistx_destroy (& l );
591+ free (cpy );
592+ return map ;
593+ error :
594+ zlistx_destroy (& l );
595+ taskmap_destroy (map );
596+ free (cpy );
597+ return NULL ;
598+ }
599+
418600struct taskmap * taskmap_decode (const char * s , flux_error_t * errp )
419601{
420602 struct taskmap * map = NULL ;
@@ -435,11 +617,17 @@ struct taskmap *taskmap_decode (const char *s, flux_error_t *errp)
435617 || strstr (s , "vector," ))
436618 return taskmap_decode_pmi (s , errp );
437619
620+ /* A string without special characters might be a raw taskmap:
621+ */
622+ if (!strpbrk (s , "({[]})" ))
623+ return taskmap_decode_raw (s , errp );
624+
625+ /* O/w, decode as RFC 34 Taskmap
626+ */
438627 if (!(o = json_loads (s , JSON_DECODE_ANY , & error ))) {
439628 errprintf (errp , "%s" , error .text );
440629 goto out ;
441630 }
442-
443631 map = taskmap_decode_json (o , errp );
444632out :
445633 json_decref (o );
@@ -675,14 +863,6 @@ static char *list_join (zlistx_t *l, char *sep)
675863 return result ;
676864}
677865
678- static void item_destructor (void * * item )
679- {
680- if (item ) {
681- free (* item );
682- * item = NULL ;
683- }
684- }
685-
686866static char * taskmap_encode_raw (const struct taskmap * map , int flags )
687867{
688868 char * result = NULL ;
0 commit comments