00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdlib.h>
00020 #include <midgard/midgard_quota.h>
00021 #include <midgard/query.h>
00022 #include <midgard/midgard_error.h>
00023 #include <sys/errno.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include "schema.h"
00027
00028 #define get_varchar_size(str) \
00029 if(str == NULL) \
00030 size++; \
00031 else \
00032 size = strlen(str) + 1 + size; \
00033 g_free(str);
00034
00035 #define get_datetime_size(str) \
00036 size = 8 + size; \
00037 g_free(str);
00038
00039 gboolean midgard_quota_size_is_reached(MgdObject *object, gint size)
00040 {
00041 GString *query;
00042 gint limit_tmp_size, tmp_size;
00043 GList *list;
00044 midgard *mgd = object->mgd;
00045 char *spacefields = NULL;
00046
00047
00048 if (mgd->quota && mgd_sitegroup(mgd) > 0) {
00049 if ((spacefields = mgd_check_quota(mgd, object->data->query->table)) == 0) {
00050 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00051 return TRUE;
00052 }
00053 }
00054
00055
00056 guint sgid;
00057 g_object_get(G_OBJECT(object), "sitegroup", &sgid, NULL);
00058 query = g_string_new("SELECT limit_sg_size, sg_size FROM quota ");
00059 g_string_append_printf(query,
00060 "WHERE typename='' and sitegroup=%d",
00061 sgid);
00062
00063 list = midgard_query_get_single_row(g_string_free(query, FALSE), object);
00064
00065
00066
00067 if(!list)
00068 return FALSE;
00069
00070 limit_tmp_size = atoi(list->data);
00071 g_free(list->data);
00072 list = list->next;
00073 tmp_size = atoi(list->data);
00074 g_free(list->data);
00075 g_list_free(list);
00076
00077 if(((tmp_size + size) > limit_tmp_size) && limit_tmp_size > 0){
00078 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00079 return TRUE;
00080 }
00081
00082
00083 query = g_string_new("SELECT limit_type_size, type_size FROM quota ");
00084 g_string_append_printf(query,
00085 "WHERE typename='%s' and sitegroup=%d",
00086 G_OBJECT_TYPE_NAME(object),
00087 midgard_sitegroup_get_id(object->mgd));
00088
00089 list = midgard_query_get_single_row(g_string_free(query, FALSE), object);
00090
00091
00092
00093 if(!list)
00094 return FALSE;
00095
00096 limit_tmp_size = atoi(list->data);
00097 g_free(list->data);
00098 list = list->next;
00099 tmp_size = atoi(list->data);
00100 g_free(list->data);
00101
00102 g_list_free(list);
00103
00104 if(((tmp_size + size) > limit_tmp_size) && limit_tmp_size > 0){
00105 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00106 return TRUE;
00107 }
00108
00109 return FALSE;
00110 }
00111
00112
00113
00114
00115
00116 guint midgard_quota_get_object_size(MgdObject *object){
00117
00118 g_assert(object != NULL);
00119
00120 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00121 GString *select = g_string_new("SELECT metadata_size");
00122 g_string_append_printf(select,
00123 " FROM %s WHERE %s=",
00124 midgard_object_class_get_table(klass),
00125 midgard_object_class_get_primary_field(klass));
00126
00127 GParamSpec *prop =
00128 g_object_class_find_property(
00129 G_OBJECT_GET_CLASS(G_OBJECT(object)),
00130 midgard_object_class_get_primary_property(klass));
00131
00132 if(prop == NULL)
00133 g_error("Primary property not found for %s", G_OBJECT_TYPE_NAME(object));
00134
00135 GValue pval = {0, };
00136 g_value_init(&pval, prop->value_type);
00137 g_object_get_property(G_OBJECT(object),
00138 midgard_object_class_get_primary_property(klass),
00139 &pval);
00140
00141 if(prop->value_type == G_TYPE_UINT) {
00142 g_string_append_printf(select,
00143 "%d",
00144 g_value_get_uint(&pval));
00145 } else {
00146 g_string_append_printf(select,
00147 "'%s'",
00148 g_value_get_string(&pval));
00149 }
00150 g_value_unset(&pval);
00151
00152
00153 guint sgid;
00154 g_object_get(G_OBJECT(object), "sitegroup", &sgid, NULL);
00155 g_string_append_printf(select,
00156 " AND sitegroup=%d",
00157 sgid);
00158
00159 gchar *query = g_string_free(select, FALSE);
00160 GList *list = midgard_query_get_single_row(query, object);
00161
00162 if(list == NULL)
00163 return 0;
00164
00165 guint size = atoi(list->data);
00166
00167 g_free(list->data);
00168 g_list_free(list);
00169
00170 return size;
00171 }
00172
00173
00174
00175
00176
00177 gboolean midgard_quota_update(MgdObject *object)
00178 {
00179 g_assert(object != NULL);
00180 g_assert(object->mgd != NULL);
00181
00182
00183 guint size = 0;
00184 guint32 qsize = 0;
00185 const gchar *typename = G_OBJECT_TYPE_NAME(object);
00186 GValue pval = {0, };
00187
00188 g_object_get(G_OBJECT(object->metadata), "size", &size, NULL);
00189
00190
00191 if(size == 0) return TRUE;
00192
00193
00194
00195
00196 qsize = midgard_quota_get_object_size(object);
00197 gint diff_size = size - qsize;
00198
00199 if(midgard_quota_size_is_reached(object, diff_size)){
00200 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00201 return FALSE;
00202 }
00203
00204 guint32 opsize;
00205 opsize = diff_size + qsize;
00206
00207
00208 if(diff_size == 0)
00209 return TRUE;
00210
00211 g_object_set(G_OBJECT(object->metadata), "size", opsize, NULL);
00212 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00213
00214 GString *query = g_string_new("UPDATE ");
00215 g_string_append_printf(query,
00216 "%s SET metadata_size=metadata_size+%d "
00217 "WHERE %s=",
00218 midgard_object_class_get_table(klass),
00219 diff_size,
00220 midgard_object_class_get_primary_field(klass));
00221
00222 GParamSpec *prop = g_object_class_find_property(
00223 G_OBJECT_GET_CLASS(G_OBJECT(object)),
00224 midgard_object_class_get_primary_property(klass));
00225
00226 g_value_init(&pval, prop->value_type);
00227 g_object_get_property(G_OBJECT(object),
00228 midgard_object_class_get_primary_property(klass),
00229 &pval);
00230
00231 if(prop->value_type == G_TYPE_UINT) {
00232 g_string_append_printf(query,
00233 "%d",
00234 g_value_get_uint(&pval));
00235 } else {
00236 g_string_append_printf(query,
00237 "'%s'",
00238 g_value_get_string(&pval));
00239 }
00240 g_value_unset(&pval);
00241 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00242
00243
00244 GString *quota_query;
00245 guint sgid;
00246 g_object_get(G_OBJECT(object), "sitegroup", &sgid, NULL);
00247 quota_query = g_string_new("UPDATE quota ");
00248 g_string_append_printf(quota_query,
00249 "SET type_size=type_size+%d "
00250 "WHERE typename='%s' AND sitegroup=%d",
00251 diff_size,
00252 typename,
00253 sgid);
00254 midgard_query_execute(object->mgd, g_string_free(quota_query, FALSE), NULL);
00255
00256
00257 quota_query = g_string_new("UPDATE quota ");
00258 g_string_append_printf(quota_query,
00259 "SET sg_size=sg_size+%d "
00260 "WHERE typename='' AND sitegroup=%d",
00261 diff_size,
00262 sgid);
00263 midgard_query_execute(object->mgd, g_string_free(quota_query, FALSE), NULL);
00264
00265
00266 return TRUE;
00267 }
00268
00269 gboolean midgard_quota_create(MgdObject *object)
00270 {
00271 g_assert(object != NULL);
00272
00273 GString *query;
00274 gint tmp_type_limit, tmp_limit;
00275 GList *list;
00276 guint object_sitegroup;
00277
00278 g_object_get(G_OBJECT(object), "sitegroup", &object_sitegroup, NULL);
00279
00280
00281 query = g_string_new("SELECT limit_sg_records, sg_records FROM quota ");
00282 g_string_append_printf(query,
00283 "WHERE typename='' and sitegroup=%d",
00284 object_sitegroup);
00285
00286 list = midgard_query_get_single_row(g_string_free(query, FALSE), object);
00287
00288
00289
00290 if(!list)
00291 return TRUE;
00292
00293
00294 tmp_type_limit = atoi(list->data);
00295 g_free(list->data);
00296 list = list->next;
00297 tmp_limit = atoi(list->data);
00298 g_free(list->data);
00299
00300 g_list_free(list);
00301
00302 if(((tmp_limit + 1) > tmp_type_limit) && tmp_type_limit > 0){
00303 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00304 return FALSE;
00305 }
00306
00307
00308 query = g_string_new("SELECT limit_type_records, type_records FROM quota ");
00309 g_string_append_printf(query,
00310 "WHERE typename='%s' and sitegroup=%d",
00311 G_OBJECT_TYPE_NAME(object),
00312 object_sitegroup);
00313
00314 list = midgard_query_get_single_row(g_string_free(query, FALSE) , object);
00315
00316
00317
00318 if(!list)
00319 return TRUE;
00320
00321 tmp_type_limit = atoi(list->data);
00322 g_free(list->data);
00323 list = list->next;
00324 tmp_limit = atoi(list->data);
00325 g_free(list->data);
00326
00327 g_list_free(list);
00328
00329 if(((tmp_limit + 1) > tmp_type_limit) && tmp_type_limit > 0){
00330 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00331 return FALSE;
00332 }
00333
00334 guint32 size;
00335 g_object_get(G_OBJECT(object->metadata), "size", &size, NULL);
00336 if(midgard_quota_size_is_reached(object, size)){
00337 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_QUOTA);
00338 return FALSE;
00339 }
00340
00341
00342 query = g_string_new("UPDATE quota ");
00343 g_string_append_printf(query,
00344 "SET type_records=type_records+1"
00345 " WHERE typename='%s' AND sitegroup=%d",
00346 G_OBJECT_TYPE_NAME(object),
00347 object_sitegroup);
00348
00349 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00350
00351
00352 query = g_string_new("UPDATE quota ");
00353 g_string_append_printf(query,
00354 "SET sg_records=sg_records+1"
00355 " WHERE typename='' AND sitegroup=%d",
00356 object_sitegroup);
00357
00358 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00359
00360 return TRUE;
00361 }
00362
00363 guint midgard_object_get_size(MgdObject *object)
00364 {
00365 g_assert(object != NULL);
00366 g_assert(object->mgd != NULL);
00367
00368
00369
00370
00371 guint propn, size = 0;
00372 const gchar *schematype, *blobdir, *strprop;
00373 const gchar *typename = G_OBJECT_TYPE_NAME(object);
00374 gchar *meta_strprop = NULL, *blobpath, *location;
00375 guint meta_intprop, i;
00376 GValue pval = {0, };
00377 struct stat statbuf;
00378
00379 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00380
00381 if(g_ascii_strcasecmp(typename, "midgard_attachment") == 0){
00382
00383 blobdir = mgd_get_blobdir(object->mgd);
00384
00385 if (!blobdir || (*blobdir != '/')
00386 || (stat(blobdir, &statbuf) != 0)
00387 || !S_ISDIR(statbuf.st_mode)) {
00388 g_error("Invalid blobdir or blobdir is not set");
00389 }
00390
00391 g_object_get(G_OBJECT(object), "location", &location, NULL);
00392
00393
00394
00395 if(strlen(location) > 1) {
00396
00397 blobpath = g_strconcat(
00398 blobdir,
00399 "/",
00400 location,
00401 NULL);
00402
00403 if((stat(blobpath, &statbuf) == 0) || (!S_ISDIR(statbuf.st_mode)))
00404 size = statbuf.st_size;
00405
00406 g_free(blobpath);
00407 }
00408 }
00409
00410 GParamSpec **props = g_object_class_list_properties(
00411 G_OBJECT_GET_CLASS(G_OBJECT(object)), &propn);
00412
00413 if(props == NULL){
00414 g_warning("Object size: Object %s has no properties",
00415 G_OBJECT_TYPE_NAME(object));
00416 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INVALID_OBJECT);
00417 return FALSE;
00418 }
00419
00420 for(i = 0; i < propn; i++){
00421
00422
00423 if(g_ascii_strcasecmp(props[i]->name, "metadata") == 0){
00424
00425
00426 g_object_get(G_OBJECT(object->metadata), "creator", &meta_strprop, NULL);
00427 get_varchar_size(meta_strprop);
00428
00429 g_object_get(G_OBJECT(object->metadata), "created", &meta_strprop, NULL);
00430 get_datetime_size(meta_strprop);
00431
00432 g_object_get(G_OBJECT(object->metadata), "revisor", &meta_strprop, NULL);
00433 get_varchar_size(meta_strprop);
00434
00435 g_object_get(G_OBJECT(object->metadata), "revised", &meta_strprop, NULL);
00436 get_datetime_size(meta_strprop);
00437
00438 g_object_get(G_OBJECT(object->metadata), "revision", &meta_intprop, NULL);
00439 size = 4 + size;
00440
00441 g_object_get(G_OBJECT(object->metadata), "locker", &meta_strprop, NULL);
00442 get_varchar_size(meta_strprop);
00443
00444 g_object_get(G_OBJECT(object->metadata), "locked", &meta_strprop, NULL);
00445 get_datetime_size(meta_strprop);
00446
00447 g_object_get(G_OBJECT(object->metadata), "approved", &meta_strprop, NULL);
00448 get_varchar_size(meta_strprop);
00449
00450 g_object_get(G_OBJECT(object->metadata), "approved", &meta_strprop, NULL);
00451 get_datetime_size(meta_strprop);
00452
00453 g_object_get(G_OBJECT(object->metadata), "authors", &meta_strprop, NULL);
00454 if(meta_strprop == NULL)
00455 meta_strprop = g_strdup("");
00456 size = strlen(meta_strprop) + 4 + size;
00457 g_free(meta_strprop);
00458
00459 g_object_get(G_OBJECT(object->metadata), "owner", &meta_strprop, NULL);
00460 get_varchar_size(meta_strprop);
00461
00462 g_object_get(G_OBJECT(object->metadata), "schedulestart", &meta_strprop, NULL);
00463 get_datetime_size(meta_strprop);
00464
00465 g_object_get(G_OBJECT(object->metadata), "scheduleend", &meta_strprop, NULL);
00466 get_datetime_size(meta_strprop);
00467
00468 g_object_get(G_OBJECT(object->metadata), "hidden", &meta_intprop, NULL);
00469 size = size;
00470
00471 g_object_get(G_OBJECT(object->metadata), "navnoentry", &meta_intprop, NULL);
00472 size = size;
00473
00474 } else {
00475
00476
00477 g_value_init(&pval, props[i]->value_type);
00478
00479 switch (props[i]->value_type){
00480
00481 case G_TYPE_FLOAT:
00482 case G_TYPE_UINT:
00483 size = 4 + size;
00484 break;
00485
00486 case G_TYPE_BOOLEAN:
00487 size = size;
00488 break;
00489
00490 case G_TYPE_STRING:
00491
00492 g_object_get_property(G_OBJECT(object), props[i]->name, &pval);
00493
00494
00495
00496 MgdSchemaPropertyAttr *prop_attr =
00497 g_hash_table_lookup(klass->data->prophash,
00498 props[i]->name);
00499 schematype = NULL;
00500 if(prop_attr != NULL)
00501 schematype = prop_attr->type;
00502
00503
00504 if((schematype == NULL)){
00505
00506 strprop = g_value_get_string(&pval);
00507 if(strprop == NULL)
00508 size++;
00509 else
00510 size = (strlen(strprop)) + 1 + size;
00511
00512 schematype = "";
00513 }
00514
00515 if(g_ascii_strcasecmp(schematype, "longtext") == 0){
00516 strprop = g_value_get_string(&pval);
00517 if(strprop == NULL)
00518 strprop = "";
00519 size = (strlen(strprop)) + 4 + size;
00520 }
00521
00522 if(g_ascii_strcasecmp(schematype, "text") == 0){
00523 strprop = g_value_get_string(&pval);
00524 if(strprop == NULL)
00525 strprop = "";
00526 size = (strlen(strprop)) + 1 + size;
00527 }
00528
00529 if(g_ascii_strcasecmp(schematype, "string") == 0){
00530 strprop = g_value_get_string(&pval); if(strprop == NULL)
00531 strprop = "";
00532 size = (strlen(strprop)) + 1 + size;
00533 }
00534
00535
00536
00537 if(g_ascii_strcasecmp(schematype, "date") == 0)
00538 size = 3 + size;
00539
00540 if(g_ascii_strcasecmp(schematype, "datetime") == 0)
00541 size = 8 + size;
00542
00543 break;
00544
00545
00546 }
00547 g_value_unset(&pval);
00548 }
00549 }
00550
00551 g_free(props);
00552
00553 return size;
00554 }
00555
00556 void midgard_quota_remove(MgdObject *object, guint size){
00557
00558 g_assert(object != NULL);
00559
00560 GString *query;
00561 const gchar *typename = G_OBJECT_TYPE_NAME(object);
00562
00563
00564 query = g_string_new("UPDATE quota ");
00565 g_string_append_printf(query,
00566 "SET type_records=type_records-1"
00567 " WHERE typename='%s' AND sitegroup=%d AND type_records>0",
00568 typename,
00569 midgard_sitegroup_get_id(object->mgd));
00570 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00571
00572
00573 query = g_string_new("UPDATE quota ");
00574 g_string_append_printf(query,
00575 "SET sg_records=sg_records-1"
00576 " WHERE typename='' AND sitegroup=%d AND sg_records>0",
00577 midgard_sitegroup_get_id(object->mgd));
00578
00579 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00580
00581 query = g_string_new("UPDATE quota ");
00582 g_string_append_printf(query,
00583 "SET type_size=type_size-%d "
00584 "WHERE typename='%s' AND sitegroup=%d AND type_size>0",
00585 size,
00586 typename,
00587 midgard_sitegroup_get_id(object->mgd));
00588 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00589
00590
00591 query = g_string_new("UPDATE quota ");
00592 g_string_append_printf(query,
00593 "SET sg_size=sg_size-%d "
00594 "WHERE typename='' AND sitegroup=%d AND sg_size>0",
00595 size,
00596 midgard_sitegroup_get_id(object->mgd));
00597 midgard_query_execute(object->mgd, g_string_free(query, FALSE), NULL);
00598
00599 }
00600
00601 typedef struct{
00602 guint sg;
00603 guint32 size;
00604 midgard *mgd;
00605 }_qts;
00606
00607
00608 static void _get_type_global_size(gpointer k, gpointer v, gpointer ud)
00609 {
00610 const gchar *typename = (gchar *)k;
00611 _qts *qts = (_qts *)ud;
00612
00613 MgdObject *object = midgard_object_new(qts->mgd, typename, NULL);
00614 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00615
00616 guint propn, i;
00617 GParamSpec **props = g_object_class_list_properties(
00618 G_OBJECT_GET_CLASS(G_OBJECT(object)), &propn);
00619
00620 if(props == NULL) return;
00621
00622 GString *tmp = g_string_new("");
00623 const gchar *nick;
00624
00625 for(i = 0; i < propn; i++){
00626
00627 nick = g_param_spec_get_nick(props[i]);
00628 if(nick && strlen(nick) > 0){
00629
00630 g_string_append_printf(tmp,
00631 "%s,",
00632 nick);
00633 }
00634 }
00635
00636 g_free(props);
00637
00638 gchar *concat = g_string_free(tmp, FALSE);
00639 guint conlen = strlen(concat);
00640
00641 if(conlen < 1){
00642 g_free(concat);
00643 return;
00644 }
00645
00646 concat[conlen-1] = '\0';
00647
00648 tmp = g_string_new("SELECT SUM(LENGTH(CONCAT(");
00649 g_string_append_printf(tmp,
00650 "%s))) FROM %s ",
00651 concat,
00652 midgard_object_class_get_tables(klass));
00653 g_string_append(tmp, " WHERE ");
00654 g_string_append_printf(tmp,
00655 "%s.sitegroup=%d",
00656 midgard_object_class_get_table(klass),
00657 qts->sg);
00658
00659 if(midgard_object_class_is_multilang(klass)){
00660
00661 g_string_append_printf(tmp,
00662 " AND %s.id=%s_i.sid ",
00663 midgard_object_class_get_table(klass),
00664 midgard_object_class_get_table(klass));
00665 }
00666
00667 g_free(concat);
00668 midgard_res *res;
00669 gchar *query = g_string_free(tmp, FALSE);
00670 res = mgd_query(qts->mgd, query);
00671 if(res && mgd_fetch(res)){
00672 qts->size = qts->size + (guint)mgd_sql2id(res,0);
00673 if(res) mgd_release(res);
00674 }
00675 g_free(query);
00676
00677 if(g_ascii_strcasecmp(typename, "midgard_attachment") == 0){
00678
00679 struct stat buf;
00680 gchar *path;
00681 const gchar *location;
00682
00683 res = mgd_query(qts->mgd,
00684 "SELECT location FROM blobs WHERE sitegroup = $d",
00685 qts->sg);
00686 if (res) {
00687 while (mgd_fetch(res)) {
00688 location = mgd_colvalue(res,0);
00689 if(location){
00690 path = g_strconcat(
00691 mgd_get_blobdir(qts->mgd),
00692 "/",
00693 location, NULL);
00694 stat(path, &buf);
00695 qts->size = qts->size + buf.st_size;
00696 g_free(path);
00697 }
00698 }
00699 mgd_release(res);
00700 }
00701 }
00702 g_object_unref(object);
00703 }
00704
00705
00706 guint32 midgard_quota_get_sitegroup_size(midgard *mgd, guint sg)
00707 {
00708
00709 g_assert(mgd != NULL);
00710 if(sg == 0) return 0;
00711
00712 if(!mgd_isroot(mgd))
00713 return 0;
00714
00715 guint32 size = 0;
00716
00717 _qts *qts = g_new(_qts,1);
00718 qts->size = 0;
00719 qts->sg = sg;
00720 qts->mgd = mgd;
00721
00722 g_hash_table_foreach(mgd->schema->types, _get_type_global_size, qts);
00723
00724 size = qts->size;
00725 g_free(qts);
00726 return size;
00727 }
00728
00729