widen the name field in database to accommodate longer strings
[profile/ivi/murphy.git] / src / resource / resource-owner.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *  * Neither the name of Intel Corporation nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34
35 #include <murphy/common/mm.h>
36 #include <murphy/common/hashtbl.h>
37 #include <murphy/common/utils.h>
38 #include <murphy/common/log.h>
39
40 #include <murphy-db/mqi.h>
41
42 #include <murphy/resource/manager-api.h>
43 #include <murphy/resource/client-api.h>
44 #include <murphy/resource/config-api.h>
45
46 #include "resource-owner.h"
47 #include "application-class.h"
48 #include "resource-set.h"
49 #include "resource.h"
50 #include "zone.h"
51 #include "resource-lua.h"
52
53 #define NAME_LENGTH          24
54 #define ATTR_LENGTH          64
55
56 #define ZONE_ID_IDX          0
57 #define ZONE_NAME_IDX        1
58 #define CLASS_NAME_IDX       2
59 #define RSET_ID_IDX          3
60 #define FIRST_ATTRIBUTE_IDX  4
61
62 typedef struct {
63     uint32_t          zone_id;
64     const char       *zone_name;
65     const char       *class_name;
66     uint32_t          rset_id;
67     mrp_attr_value_t  attrs[MQI_COLUMN_MAX];
68 } owner_row_t;
69
70 static mrp_resource_owner_t  resource_owners[MRP_ZONE_MAX * MRP_RESOURCE_MAX];
71 static mqi_handle_t          owner_tables[MRP_RESOURCE_MAX];
72
73 static mrp_resource_owner_t *get_owner(uint32_t, uint32_t);
74 static void reset_owners(uint32_t, mrp_resource_owner_t *);
75 static bool grant_ownership(mrp_resource_owner_t *, mrp_zone_t *,
76                             mrp_application_class_t *, mrp_resource_set_t *,
77                             mrp_resource_t *);
78 static bool advice_ownership(mrp_resource_owner_t *, mrp_zone_t *,
79                              mrp_application_class_t *, mrp_resource_set_t *,
80                              mrp_resource_t *);
81
82 static void manager_start_transaction(mrp_zone_t *);
83 static void manager_end_transaction(mrp_zone_t *);
84
85 static void delete_resource_owner(mrp_zone_t *, mrp_resource_t *);
86 static void insert_resource_owner(mrp_zone_t *, mrp_application_class_t *,
87                                   mrp_resource_set_t *, mrp_resource_t *);
88 static void update_resource_owner(mrp_zone_t *, mrp_application_class_t *,
89                                   mrp_resource_set_t *, mrp_resource_t *);
90 static void set_attr_descriptors(mqi_column_desc_t *, mrp_resource_t *);
91
92
93 int mrp_resource_owner_create_database_table(mrp_resource_def_t *rdef)
94 {
95     MQI_COLUMN_DEFINITION_LIST(base_coldefs,
96         MQI_COLUMN_DEFINITION( "zone_id"          , MQI_UNSIGNED             ),
97         MQI_COLUMN_DEFINITION( "zone_name"        , MQI_VARCHAR(NAME_LENGTH) ),
98         MQI_COLUMN_DEFINITION( "application_class", MQI_VARCHAR(NAME_LENGTH) ),
99         MQI_COLUMN_DEFINITION( "resource_set_id"  , MQI_UNSIGNED             )
100     );
101
102     MQI_INDEX_DEFINITION(indexdef,
103         MQI_INDEX_COLUMN( "zone_id" )
104     );
105
106     static bool initialized = false;
107
108     char name[256];
109     mqi_column_def_t coldefs[MQI_COLUMN_MAX + 1];
110     mqi_column_def_t *col;
111     mrp_attr_def_t *atd;
112     mqi_handle_t table;
113     char c, *p;
114     size_t i,j;
115
116     if (!initialized) {
117         mqi_open();
118         for (i = 0;  i < MRP_RESOURCE_MAX;  i++)
119             owner_tables[i] = MQI_HANDLE_INVALID;
120         initialized = true;
121     }
122
123     MRP_ASSERT(sizeof(base_coldefs) < sizeof(coldefs),"too many base columns");
124     MRP_ASSERT(rdef, "invalid argument");
125     MRP_ASSERT(rdef->id < MRP_RESOURCE_MAX, "confused with data structures");
126     MRP_ASSERT(owner_tables[rdef->id] == MQI_HANDLE_INVALID,
127                "owner table already exist");
128
129     snprintf(name, sizeof(name), "%s_owner", rdef->name);
130     for (p = name; (c = *p);  p++) {
131         if (!isascii(c) || (!isalnum(c) && c != '_'))
132             *p = '_';
133     }
134
135     j = MQI_DIMENSION(base_coldefs) - 1;
136     memcpy(coldefs, base_coldefs, j * sizeof(mqi_column_def_t));
137
138     for (i = 0;  i < rdef->nattr && j < MQI_COLUMN_MAX;  i++, j++) {
139         col = coldefs + j;
140         atd = rdef->attrdefs + i;
141
142         col->name   = atd->name;
143         col->type   = atd->type;
144         col->length = (col->type == mqi_string) ? ATTR_LENGTH : 0;
145         col->flags  = 0;
146     }
147
148     memset(coldefs + j, 0, sizeof(mqi_column_def_t));
149
150     table = MQI_CREATE_TABLE(name, MQI_TEMPORARY, coldefs, indexdef);
151
152     if (table == MQI_HANDLE_INVALID) {
153         mrp_log_error("Can't create table '%s': %s", name, strerror(errno));
154         return -1;
155     }
156
157     owner_tables[rdef->id] = table;
158
159     return 0;
160 }
161
162 void mrp_resource_owner_recalc(uint32_t zoneid)
163 {
164     mrp_resource_owner_update_zone(zoneid, NULL, 0);
165 }
166
167 void mrp_resource_owner_update_zone(uint32_t zoneid,
168                                     mrp_resource_set_t *reqset,
169                                     uint32_t reqid)
170 {
171     typedef struct {
172         uint32_t replyid;
173         mrp_resource_set_t *rset;
174         bool move;
175     } event_t;
176
177     mrp_resource_owner_t oldowners[MRP_RESOURCE_MAX];
178     mrp_resource_owner_t backup[MRP_RESOURCE_MAX];
179     mrp_zone_t *zone;
180     mrp_application_class_t *class;
181     mrp_resource_set_t *rset;
182     mrp_resource_t *res;
183     mrp_resource_def_t *rdef;
184     mrp_resource_mgr_ftbl_t *ftbl;
185     mrp_resource_owner_t *owner, *old, *owners;
186     mrp_resource_mask_t mask;
187     mrp_resource_mask_t mandatory;
188     mrp_resource_mask_t grant;
189     mrp_resource_mask_t advice;
190     void *clc, *rsc, *rc;
191     uint32_t rid;
192     uint32_t rcnt;
193     bool force_release;
194     bool changed;
195     bool move;
196     mrp_resource_event_t notify;
197     uint32_t replyid;
198     uint32_t nevent, maxev;
199     event_t *events, *ev, *lastev;
200     mqi_handle_t trans_handle;
201
202     MRP_ASSERT(zoneid < MRP_ZONE_MAX, "invalid argument");
203
204     zone = mrp_zone_find_by_id(zoneid);
205
206     MRP_ASSERT(zone, "zone is not defined");
207
208     if (!(maxev = mrp_get_resource_set_count()))
209         return;
210
211     nevent = 0;
212     events = mrp_alloc(sizeof(event_t) * maxev);
213
214     MRP_ASSERT(events, "Memory alloc failure. Can't update zone");
215
216     reset_owners(zoneid, oldowners);
217     manager_start_transaction(zone);
218
219     rcnt = mrp_resource_definition_count();
220     clc  = NULL;
221
222     while ((class = mrp_application_class_iterate_classes(&clc))) {
223         rsc = NULL;
224
225         while ((rset=mrp_application_class_iterate_rsets(class,zoneid,&rsc))) {
226             force_release = false;
227             mandatory = rset->resource.mask.mandatory;
228             grant = 0;
229             advice = 0;
230             rc = NULL;
231
232             switch (rset->state) {
233
234             case mrp_resource_acquire:
235                 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
236                     rdef  = res->def;
237                     rid   = rdef->id;
238                     owner = get_owner(zoneid, rid);
239
240                     backup[rid] = *owner;
241
242                     if (grant_ownership(owner, zone, class, rset, res))
243                         grant |= ((mrp_resource_mask_t)1 << rid);
244                     else {
245                         if (owner->rset != rset)
246                             force_release |= owner->modal;
247                     }
248                 }
249                 owners = get_owner(zoneid, 0);
250                 if ((grant & mandatory) == mandatory &&
251                     mrp_resource_lua_veto(zone, rset, owners, grant, reqset))
252                 {
253                     advice = grant;
254                 }
255                 else {
256                     /* rollback, ie. restore the backed up state */
257                     rc = NULL;
258                     while ((res=mrp_resource_set_iterate_resources(rset,&rc))){
259                         rdef = res->def;
260                         rid = rdef->id;
261                         mask = (mrp_resource_mask_t)1 << rid;
262                         owner = get_owner(zoneid, rid);
263                         *owner = backup[rid];
264
265                         if ((grant & mask)) {
266                             if ((ftbl = rdef->manager.ftbl) && ftbl->free)
267                                 ftbl->free(zone, res, rdef->manager.userdata);
268                         }
269
270                         if (advice_ownership(owner, zone, class, rset, res))
271                             advice |= mask;
272                     }
273
274                     grant = 0;
275
276                     if ((advice & mandatory) != mandatory)
277                         advice = 0;
278
279                     mrp_resource_lua_set_owners(zone, owners);
280                 }
281                 break;
282
283             case mrp_resource_release:
284                 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
285                     rdef  = res->def;
286                     rid   = rdef->id;
287                     owner = get_owner(zoneid, rid);
288
289                     if (advice_ownership(owner, zone, class, rset, res))
290                         advice |= ((mrp_resource_mask_t)1 << rid);
291                 }
292                 if ((advice & mandatory) != mandatory)
293                     advice = 0;
294                 break;
295
296             default:
297                 break;
298             }
299
300             changed = false;
301             move    = false;
302             notify  = 0;
303             replyid = (reqset == rset && reqid == rset->request.id) ? reqid:0;
304
305
306             if (force_release) {
307                 move = (rset->state != mrp_resource_release);
308                 notify = move ? MRP_RESOURCE_EVENT_RELEASE : 0;
309                 changed = move || rset->resource.mask.grant;
310                 rset->state = mrp_resource_release;
311                 rset->resource.mask.grant = 0;
312             }
313             else {
314                 if (grant == rset->resource.mask.grant) {
315                     if (rset->state == mrp_resource_acquire &&
316                         !grant && rset->dont_wait.current)
317                     {
318                         rset->state = mrp_resource_release;
319                         rset->dont_wait.current = rset->dont_wait.client;
320
321                         notify = MRP_RESOURCE_EVENT_RELEASE;
322                         move = true;
323                     }
324                 }
325                 else {
326                     rset->resource.mask.grant = grant;
327                     changed = true;
328
329                     if (rset->state != mrp_resource_release &&
330                         !grant && rset->auto_release.current)
331                     {
332                         rset->state = mrp_resource_release;
333                         rset->auto_release.current = rset->auto_release.client;
334
335                         notify = MRP_RESOURCE_EVENT_RELEASE;
336                         move = true;
337                     }
338                 }
339             }
340
341             if (notify) {
342                 mrp_resource_set_notify(rset, notify);
343             }
344
345             if (advice != rset->resource.mask.advice) {
346                 rset->resource.mask.advice = advice;
347                 changed = true;
348             }
349
350             if (replyid || changed) {
351                 ev = events + nevent++;
352
353                 ev->replyid = replyid;
354                 ev->rset    = rset;
355                 ev->move    = move;
356             }
357         } /* while rset */
358     } /* while class */
359
360     manager_end_transaction(zone);
361
362     for (lastev = (ev = events) + nevent;     ev < lastev;     ev++) {
363         rset = ev->rset;
364
365         if (ev->move)
366             mrp_application_class_move_resource_set(rset);
367
368         mrp_resource_set_updated(rset);
369
370         /* first we send out the revoke/deny events
371          * followed by the grants (in the next for loop)
372          */
373         if (rset->event && !rset->resource.mask.grant)
374             rset->event(ev->replyid, rset, rset->user_data);
375     }
376
377     for (lastev = (ev = events) + nevent;     ev < lastev;     ev++) {
378         rset = ev->rset;
379
380         if (rset->event && rset->resource.mask.grant)
381             rset->event(ev->replyid, rset, rset->user_data);
382     }
383
384     mrp_free(events);
385
386     trans_handle = MQI_HANDLE_INVALID;
387
388     for (rid = 0;  rid < rcnt;  rid++) {
389         owner = get_owner(zoneid, rid);
390         old   = oldowners + rid;
391
392         if (owner->class != old->class ||
393             owner->rset  != old->rset  ||
394             owner->res   != old->res     )
395         {
396             if (trans_handle == MQI_HANDLE_INVALID)
397                 trans_handle = MQI_BEGIN;
398
399             if (!owner->res)
400                delete_resource_owner(zone,old->res);
401             else if (!old->res)
402                insert_resource_owner(zone,owner->class,owner->rset,owner->res);
403             else
404                update_resource_owner(zone,owner->class,owner->rset,owner->res);
405         }
406     }
407
408     if (trans_handle != MQI_HANDLE_INVALID)
409         MQI_COMMIT(trans_handle);
410 }
411
412 int mrp_resource_owner_print(char *buf, int len)
413 {
414 #define PRINT(fmt, args...)  if (p<e) { p += snprintf(p, e-p, fmt , ##args); }
415
416     mrp_zone_t *zone;
417     mrp_resource_owner_t *owner;
418     mrp_application_class_t *class;
419     mrp_resource_set_t *rset;
420     mrp_resource_t *res;
421     mrp_resource_def_t *rdef;
422     uint32_t rcnt, rid;
423     uint32_t zcnt, zid;
424     char *p, *e;
425
426     if (len <= 0)
427         return 0;
428
429     MRP_ASSERT(buf, "invalid argument");
430
431     rcnt = mrp_resource_definition_count();
432     zcnt = mrp_zone_count();
433
434     e = (p = buf) + len;
435
436     PRINT("Resource owners:\n");
437
438     for (zid = 0;  zid < zcnt;  zid++) {
439         zone = mrp_zone_find_by_id(zid);
440
441         if (!zone) {
442             PRINT("   Zone %u:\n", zid);
443         }
444         else {
445             PRINT("   Zone %s:", zone->name);
446             p += mrp_zone_attribute_print(zone, p, e-p);
447             PRINT("\n");
448         }
449
450         for (rid = 0;   rid < rcnt;   rid++) {
451             if (!(rdef = mrp_resource_definition_find_by_id(rid)))
452                 continue;
453
454             PRINT("      %-15s: ", rdef->name);
455
456             owner = get_owner(zid, rid);
457
458             if (!(class = owner->class) ||
459                 !(rset  = owner->rset ) ||
460                 !(res   = owner->res  )    )
461             {
462                 PRINT("<nobody>");
463             }
464             else {
465                 MRP_ASSERT(rdef == res->def, "confused with data structures");
466
467                 PRINT("%-15s", class->name);
468
469                 p += mrp_resource_attribute_print(res, p, e-p);
470             }
471
472             PRINT("\n");
473         }
474     }
475
476     return p - buf;
477
478 #undef PRINT
479 }
480
481
482 static mrp_resource_owner_t *get_owner(uint32_t zone, uint32_t resid)
483 {
484     MRP_ASSERT(zone < MRP_ZONE_MAX && resid < MRP_RESOURCE_MAX,
485                "invalid argument");
486
487     return resource_owners + (zone * MRP_RESOURCE_MAX + resid);
488 }
489
490 static void reset_owners(uint32_t zone, mrp_resource_owner_t *oldowners)
491 {
492     mrp_resource_owner_t *owners = get_owner(zone, 0);
493     size_t size = sizeof(mrp_resource_owner_t) * MRP_RESOURCE_MAX;
494     size_t i;
495
496     if (oldowners)
497         memcpy(oldowners, owners, size);
498
499     memset(owners, 0, size);
500
501     for (i = 0;   i < MRP_RESOURCE_MAX;   i++)
502         owners[i].share = true;
503 }
504
505 static bool grant_ownership(mrp_resource_owner_t    *owner,
506                             mrp_zone_t              *zone,
507                             mrp_application_class_t *class,
508                             mrp_resource_set_t      *rset,
509                             mrp_resource_t          *res)
510 {
511     mrp_resource_def_t      *rdef = res->def;
512     mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
513     bool                     set_owner = false;
514
515     /*
516       if (forbid_grant())
517         return false;
518      */
519
520     if (owner->modal)
521         return false;
522
523     do { /* not a loop */
524         if (!owner->class && !owner->rset) {
525             /* nobody owns this, so grab it */
526             set_owner = true;
527             break;
528         }
529
530         if (owner->class == class && owner->rset == rset) {
531             /* we happen to already own it */
532             break;
533         }
534
535         if (rdef->shareable && owner->share) {
536             /* OK, someone else owns it but
537                the owner is ready to share it with us */
538             break;
539         }
540
541         return false;
542
543     } while(0);
544
545     if (ftbl && ftbl->allocate) {
546         if (!ftbl->allocate(zone, res, rdef->manager.userdata))
547             return false;
548     }
549
550     if (set_owner) {
551         owner->class = class;
552         owner->rset  = rset;
553         owner->res   = res;
554         owner->modal = class->modal;
555     }
556
557     owner->share = class->share && res->shared;
558
559     return true;
560 }
561
562 static bool advice_ownership(mrp_resource_owner_t    *owner,
563                              mrp_zone_t              *zone,
564                              mrp_application_class_t *class,
565                              mrp_resource_set_t      *rset,
566                              mrp_resource_t          *res)
567 {
568     mrp_resource_def_t      *rdef = res->def;
569     mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
570
571     (void)zone;
572
573     /*
574       if (forbid_grant())
575         return false;
576      */
577
578     if (owner->modal)
579         return false;
580
581     do { /* not a loop */
582         if (!owner->class && !owner->rset)
583             /* nobody owns this */
584             break;
585
586         if (owner->share)
587             /* someone else owns it but it can be shared */
588             break;
589
590         if (owner->class == class) {
591             if (owner->rset->class.priority == rset->class.priority &&
592                     class->order == MRP_RESOURCE_ORDER_LIFO)
593                 /* same class and resource goes to the last one who asks it */
594                 break;
595         }
596
597         return false;
598
599     } while(0);
600
601     if (ftbl && ftbl->advice) {
602         if (!ftbl->advice(zone, res, rdef->manager.userdata))
603             return false;
604     }
605
606     return true;
607 }
608
609 static void manager_start_transaction(mrp_zone_t *zone)
610 {
611     mrp_resource_def_t *rdef;
612     mrp_resource_mgr_ftbl_t *ftbl;
613     void *cursor = NULL;
614
615     while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
616         ftbl = rdef->manager.ftbl;
617
618         MRP_ASSERT(ftbl, "confused with data structures");
619
620         if (ftbl->init)
621             ftbl->init(zone, rdef->manager.userdata);
622     }
623 }
624
625 static void manager_end_transaction(mrp_zone_t *zone)
626 {
627     mrp_resource_def_t *rdef;
628     mrp_resource_mgr_ftbl_t *ftbl;
629     void *cursor = NULL;
630
631     while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
632         ftbl = rdef->manager.ftbl;
633
634         MRP_ASSERT(ftbl, "confused with data structures");
635
636         if (ftbl->commit)
637             ftbl->commit(zone, rdef->manager.userdata);
638     }
639 }
640
641
642 static void delete_resource_owner(mrp_zone_t *zone, mrp_resource_t *res)
643 {
644     static uint32_t zone_id;
645
646     MQI_WHERE_CLAUSE(where,
647         MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
648     );
649
650     mrp_resource_def_t *rdef;
651     int n;
652
653     MRP_ASSERT(res, "invalid argument");
654
655     rdef = res->def;
656     zone_id = zone->id;
657
658     if ((n = MQI_DELETE(owner_tables[rdef->id], where)) != 1)
659         mrp_log_error("Could not delete resource owner");
660 }
661
662 static void insert_resource_owner(mrp_zone_t *zone,
663                                   mrp_application_class_t *class,
664                                   mrp_resource_set_t *rset,
665                                   mrp_resource_t *res)
666 {
667     mrp_resource_def_t *rdef = res->def;
668     uint32_t i;
669     int n;
670     owner_row_t row;
671     owner_row_t *rows[2];
672     mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
673
674     MRP_ASSERT(FIRST_ATTRIBUTE_IDX + rdef->nattr <= MQI_COLUMN_MAX,
675                "too many attributes for a table");
676
677     row.zone_id    = zone->id;
678     row.zone_name  = zone->name;
679     row.class_name = class->name;
680     row.rset_id    = rset->id;
681     memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
682
683     i = 0;
684     cdsc[i].cindex = ZONE_ID_IDX;
685     cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_id);
686
687     i++;
688     cdsc[i].cindex = ZONE_NAME_IDX;
689     cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_name);
690
691     i++;
692     cdsc[i].cindex = CLASS_NAME_IDX;
693     cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
694
695     i++;
696     cdsc[i].cindex = RSET_ID_IDX;
697     cdsc[i].offset = MQI_OFFSET(owner_row_t, rset_id);
698     
699     set_attr_descriptors(cdsc + (i+1), res);
700
701     rows[0] = &row;
702     rows[1] = NULL;
703
704     if ((n = MQI_INSERT_INTO(owner_tables[rdef->id], cdsc, rows)) != 1)
705         mrp_log_error("can't insert row into owner table");
706 }
707
708 static void update_resource_owner(mrp_zone_t *zone,
709                                   mrp_application_class_t *class,
710                                   mrp_resource_set_t *rset,
711                                   mrp_resource_t *res)
712 {
713     static uint32_t zone_id;
714
715     MQI_WHERE_CLAUSE(where,
716         MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
717     );
718
719     mrp_resource_def_t *rdef = res->def;
720     uint32_t i;
721     int n;
722     owner_row_t row;
723     mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
724
725     zone_id = zone->id;
726
727     MRP_ASSERT(1 + rdef->nattr <= MQI_COLUMN_MAX,
728                "too many attributes for a table");
729
730     row.class_name = class->name;
731     row.rset_id    = rset->id;
732     memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
733
734     i = 0;
735     cdsc[i].cindex = CLASS_NAME_IDX;
736     cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
737
738     i++;
739     cdsc[i].cindex = RSET_ID_IDX;
740     cdsc[i].offset = MQI_OFFSET(owner_row_t, rset_id);
741
742     set_attr_descriptors(cdsc + (i+1), res);
743
744
745     if ((n = MQI_UPDATE(owner_tables[rdef->id], cdsc, &row, where)) != 1)
746         mrp_log_error("can't update row in owner table");
747 }
748
749
750 static void set_attr_descriptors(mqi_column_desc_t *cdsc, mrp_resource_t *res)
751 {
752     mrp_resource_def_t *rdef = res->def;
753     uint32_t i,j;
754     int o;
755
756     for (i = j = 0;  j < rdef->nattr;  j++) {
757         switch (rdef->attrdefs[j].type) {
758         case mqi_string:   o = MQI_OFFSET(owner_row_t,attrs[j].string);  break;
759         case mqi_integer:  o = MQI_OFFSET(owner_row_t,attrs[j].integer); break;
760         case mqi_unsignd:  o = MQI_OFFSET(owner_row_t,attrs[j].unsignd); break;
761         case mqi_floating: o = MQI_OFFSET(owner_row_t,attrs[j].floating);break;
762         default:           /* skip this */                            continue;
763         }
764
765         cdsc[i].cindex = FIRST_ATTRIBUTE_IDX + j;
766         cdsc[i].offset = o;
767         i++;
768     }
769
770     cdsc[i].cindex = -1;
771     cdsc[i].offset =  1;
772 }
773
774
775 /*
776  * Local Variables:
777  * c-basic-offset: 4
778  * indent-tabs-mode: nil
779  * End:
780  *
781  */