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