~ubuntu-branches/ubuntu/quantal/ceph/quantal

« back to all changes in this revision

Viewing changes to src/cls_rgw.cc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-07-16 09:56:24 UTC
  • mfrom: (0.3.11)
  • mto: This revision was merged to the branch mainline in revision 17.
  • Revision ID: package-import@ubuntu.com-20120716095624-azr2w4hbhei1rxmx
Tags: upstream-0.48
ImportĀ upstreamĀ versionĀ 0.48

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 
2
// vim: ts=8 sw=2 smarttab
 
3
 
1
4
#include <iostream>
2
5
 
3
6
#include <string.h>
21
24
cls_method_handle_t h_rgw_bucket_prepare_op;
22
25
cls_method_handle_t h_rgw_bucket_complete_op;
23
26
cls_method_handle_t h_rgw_dir_suggest_changes;
 
27
cls_method_handle_t h_rgw_user_usage_log_add;
 
28
cls_method_handle_t h_rgw_user_usage_log_read;
 
29
cls_method_handle_t h_rgw_user_usage_log_trim;
24
30
 
25
31
 
26
32
#define ROUND_BLOCK_SIZE 4096
38
44
  try {
39
45
    ::decode(op, iter);
40
46
  } catch (buffer::error& err) {
41
 
    CLS_LOG("ERROR: rgw_bucket_list(): failed to decode request\n");
 
47
    CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode request\n");
42
48
    return -EINVAL;
43
49
  }
44
50
 
52
58
  try {
53
59
    ::decode(new_dir.header, header_iter);
54
60
  } catch (buffer::error& err) {
55
 
    CLS_LOG("ERROR: rgw_bucket_list(): failed to decode header\n");
 
61
    CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode header\n");
56
62
    return -EINVAL;
57
63
  }
58
64
 
59
65
  bufferlist bl;
60
66
 
61
67
  map<string, bufferlist> keys;
62
 
  rc = cls_cxx_map_read_keys(hctx, op.start_obj, op.filter_prefix, op.num_entries + 1, &keys);
 
68
  rc = cls_cxx_map_get_vals(hctx, op.start_obj, op.filter_prefix, op.num_entries + 1, &keys);
63
69
  if (rc < 0)
64
70
    return rc;
65
71
 
74
80
    try {
75
81
      ::decode(entry, eiter);
76
82
    } catch (buffer::error& err) {
77
 
      CLS_LOG("ERROR: rgw_bucket_list(): failed to decode entry, key=%s\n", kiter->first.c_str());
 
83
      CLS_LOG(1, "ERROR: rgw_bucket_list(): failed to decode entry, key=%s\n", kiter->first.c_str());
78
84
      return -EINVAL;
79
85
    }
80
86
    
105
111
  }
106
112
 
107
113
  if (header_bl.length() != 0) {
108
 
    CLS_LOG("ERROR: index already initialized\n");
 
114
    CLS_LOG(1, "ERROR: index already initialized\n");
109
115
    return -EINVAL;
110
116
  }
111
117
 
123
129
  try {
124
130
    ::decode(op, iter);
125
131
  } catch (buffer::error& err) {
126
 
    CLS_LOG("ERROR: rgw_bucket_prepare_op(): failed to decode request\n");
 
132
    CLS_LOG(1, "ERROR: rgw_bucket_prepare_op(): failed to decode request\n");
127
133
    return -EINVAL;
128
134
  }
129
135
 
130
136
  if (op.tag.empty()) {
131
 
    CLS_LOG("ERROR: tag is empty\n");
 
137
    CLS_LOG(1, "ERROR: tag is empty\n");
132
138
    return -EINVAL;
133
139
  }
134
140
 
135
 
  CLS_LOG("rgw_bucket_prepare_op(): request: op=%d name=%s tag=%s\n", op.op, op.name.c_str(), op.tag.c_str());
 
141
  CLS_LOG(1, "rgw_bucket_prepare_op(): request: op=%d name=%s tag=%s\n", op.op, op.name.c_str(), op.tag.c_str());
136
142
 
137
143
  // get on-disk state
138
144
  bufferlist cur_value;
139
 
  int rc = cls_cxx_map_read_key(hctx, op.name, &cur_value);
 
145
  int rc = cls_cxx_map_get_val(hctx, op.name, &cur_value);
140
146
  if (rc < 0 && rc != -ENOENT)
141
147
    return rc;
142
148
 
151
157
      bufferlist::iterator biter = cur_value.begin();
152
158
      ::decode(entry, biter);
153
159
    } catch (buffer::error& err) {
154
 
      CLS_LOG("ERROR: rgw_bucket_prepare_op(): failed to decode entry\n");
 
160
      CLS_LOG(1, "ERROR: rgw_bucket_prepare_op(): failed to decode entry\n");
155
161
      /* ignoring error */
156
162
 
157
163
      noent = true;
174
180
  // write out new key to disk
175
181
  bufferlist info_bl;
176
182
  ::encode(entry, info_bl);
177
 
  cls_cxx_map_write_key(hctx, op.name, &info_bl);
 
183
  cls_cxx_map_set_val(hctx, op.name, &info_bl);
178
184
  return rc;
179
185
}
180
186
 
186
192
  try {
187
193
    ::decode(op, iter);
188
194
  } catch (buffer::error& err) {
189
 
    CLS_LOG("ERROR: rgw_bucket_complete_op(): failed to decode request\n");
 
195
    CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode request\n");
190
196
    return -EINVAL;
191
197
  }
192
 
  CLS_LOG("rgw_bucket_complete_op(): request: op=%d name=%s epoch=%lld tag=%s\n", op.op, op.name.c_str(), op.epoch, op.tag.c_str());
 
198
  CLS_LOG(1, "rgw_bucket_complete_op(): request: op=%d name=%s epoch=%lld tag=%s\n", op.op, op.name.c_str(), op.epoch, op.tag.c_str());
193
199
 
194
200
  bufferlist header_bl;
195
201
  struct rgw_bucket_dir_header header;
200
206
  try {
201
207
    ::decode(header, header_iter);
202
208
  } catch (buffer::error& err) {
203
 
    CLS_LOG("ERROR: rgw_bucket_complete_op(): failed to decode header\n");
 
209
    CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode header\n");
204
210
    return -EINVAL;
205
211
  }
206
212
 
207
213
  bufferlist current_entry;
208
214
  struct rgw_bucket_dir_entry entry;
209
215
  bool ondisk = true;
210
 
  rc = cls_cxx_map_read_key(hctx, op.name, &current_entry);
 
216
  rc = cls_cxx_map_get_val(hctx, op.name, &current_entry);
211
217
  if (rc < 0) {
212
218
    if (rc != -ENOENT) {
213
219
      return rc;
223
229
    bufferlist::iterator cur_iter = current_entry.begin();
224
230
    try {
225
231
      ::decode(entry, cur_iter);
226
 
      CLS_LOG("rgw_bucket_complete_op(): existing entry: epoch=%lld name=%s locator=%s\n", entry.epoch, entry.name.c_str(), entry.locator.c_str());
 
232
      CLS_LOG(1, "rgw_bucket_complete_op(): existing entry: epoch=%lld name=%s locator=%s\n", entry.epoch, entry.name.c_str(), entry.locator.c_str());
227
233
    } catch (buffer::error& err) {
228
 
      CLS_LOG("ERROR: rgw_bucket_complete_op(): failed to decode entry\n");
 
234
      CLS_LOG(1, "ERROR: rgw_bucket_complete_op(): failed to decode entry\n");
229
235
    }
230
236
  }
231
237
 
232
238
  if (op.tag.size()) {
233
239
    map<string, struct rgw_bucket_pending_info>::iterator pinter = entry.pending_map.find(op.tag);
234
240
    if (pinter == entry.pending_map.end()) {
235
 
      CLS_LOG("ERROR: couldn't find tag for pending operation\n");
 
241
      CLS_LOG(1, "ERROR: couldn't find tag for pending operation\n");
236
242
      return -EINVAL;
237
243
    }
238
244
    entry.pending_map.erase(pinter);
242
248
  bufferlist update_bl;
243
249
 
244
250
  if (op.tag.size() && op.op == CLS_RGW_OP_CANCEL) {
245
 
    CLS_LOG("rgw_bucket_complete_op(): cancel requested\n");
 
251
    CLS_LOG(1, "rgw_bucket_complete_op(): cancel requested\n");
246
252
    cancel = true;
247
253
  } else if (op.epoch <= entry.epoch) {
248
 
    CLS_LOG("rgw_bucket_complete_op(): skipping request, old epoch\n");
 
254
    CLS_LOG(1, "rgw_bucket_complete_op(): skipping request, old epoch\n");
249
255
    cancel = true;
250
256
  }
251
257
 
254
260
    if (op.tag.size()) {
255
261
      bufferlist new_key_bl;
256
262
      ::encode(entry, new_key_bl);
257
 
      return cls_cxx_map_write_key(hctx, op.name, &new_key_bl);
 
263
      return cls_cxx_map_set_val(hctx, op.name, &new_key_bl);
258
264
    } else {
259
265
      return 0;
260
266
    }
278
284
        entry.exists = false;
279
285
        bufferlist new_key_bl;
280
286
        ::encode(entry, new_key_bl);
281
 
        int ret = cls_cxx_map_write_key(hctx, op.name, &new_key_bl);
 
287
        int ret = cls_cxx_map_set_val(hctx, op.name, &new_key_bl);
282
288
        if (ret < 0)
283
289
          return ret;
284
290
      }
299
305
      stats.total_size_rounded += get_rounded_size(meta.size);
300
306
      bufferlist new_key_bl;
301
307
      ::encode(entry, new_key_bl);
302
 
      int ret = cls_cxx_map_write_key(hctx, op.name, &new_key_bl);
 
308
      int ret = cls_cxx_map_set_val(hctx, op.name, &new_key_bl);
303
309
      if (ret < 0)
304
310
        return ret;
305
311
    }
313
319
 
314
320
int rgw_dir_suggest_changes(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
315
321
{
316
 
  CLS_LOG("rgw_dir_suggest_changes()");
 
322
  CLS_LOG(1, "rgw_dir_suggest_changes()");
317
323
 
318
324
  bufferlist header_bl;
319
325
  struct rgw_bucket_dir_header header;
326
332
    bufferlist::iterator header_iter = header_bl.begin();
327
333
    ::decode(header, header_iter);
328
334
  } catch (buffer::error& error) {
329
 
    CLS_LOG("ERROR: rgw_dir_suggest_changes(): failed to decode header\n");
 
335
    CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode header\n");
330
336
    return -EINVAL;
331
337
  }
332
338
 
341
347
      ::decode(op, in_iter);
342
348
      ::decode(cur_change, in_iter);
343
349
    } catch (buffer::error& err) {
344
 
      CLS_LOG("ERROR: rgw_dir_suggest_changes(): failed to decode request\n");
 
350
      CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode request\n");
345
351
      return -EINVAL;
346
352
    }
347
353
 
348
354
    bufferlist cur_disk_bl;
349
 
    int ret = cls_cxx_map_read_key(hctx, cur_change.name, &cur_disk_bl);
 
355
    int ret = cls_cxx_map_get_val(hctx, cur_change.name, &cur_disk_bl);
350
356
    if (ret < 0 && ret != -ENOENT)
351
357
      return -EINVAL;
352
358
 
355
361
      try {
356
362
        ::decode(cur_disk, cur_disk_iter);
357
363
      } catch (buffer::error& error) {
358
 
        CLS_LOG("ERROR: rgw_dir_suggest_changes(): failed to decode cur_disk\n");
 
364
        CLS_LOG(1, "ERROR: rgw_dir_suggest_changes(): failed to decode cur_disk\n");
359
365
        return -EINVAL;
360
366
      }
361
367
 
391
397
        stats.total_size_rounded += get_rounded_size(cur_change.meta.size);
392
398
        bufferlist cur_state_bl;
393
399
        ::encode(cur_change, cur_state_bl);
394
 
        ret = cls_cxx_map_write_key(hctx, cur_change.name, &cur_state_bl);
 
400
        ret = cls_cxx_map_set_val(hctx, cur_change.name, &cur_state_bl);
395
401
        if (ret < 0)
396
402
          return ret;
397
403
        break;
408
414
  return 0;
409
415
}
410
416
 
 
417
static void usage_record_prefix_by_time(uint64_t epoch, string& key)
 
418
{
 
419
  char buf[32];
 
420
  snprintf(buf, sizeof(buf), "%011llu", (long long unsigned)epoch);
 
421
  key = buf;
 
422
}
 
423
 
 
424
static void usage_record_name_by_time(uint64_t epoch, string& user, string& bucket, string& key)
 
425
{
 
426
  char buf[32 + user.size() + bucket.size()];
 
427
  snprintf(buf, sizeof(buf), "%011llu_%s_%s", (long long unsigned)epoch, user.c_str(), bucket.c_str());
 
428
  key = buf;
 
429
}
 
430
 
 
431
static void usage_record_name_by_user(string& user, uint64_t epoch, string& bucket, string& key)
 
432
{
 
433
  char buf[32 + user.size() + bucket.size()];
 
434
  snprintf(buf, sizeof(buf), "%s_%011llu_%s", user.c_str(), (long long unsigned)epoch, bucket.c_str());
 
435
  key = buf;
 
436
}
 
437
 
 
438
static int usage_record_decode(bufferlist& record_bl, rgw_usage_log_entry& e)
 
439
{
 
440
  bufferlist::iterator kiter = record_bl.begin();
 
441
  try {
 
442
    ::decode(e, kiter);
 
443
  } catch (buffer::error& err) {
 
444
    CLS_LOG(1, "ERROR: usage_record_decode(): failed to decode record_bl\n");
 
445
    return -EINVAL;
 
446
  }
 
447
 
 
448
  return 0;
 
449
}
 
450
 
 
451
int rgw_user_usage_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
 
452
{
 
453
  CLS_LOG(10, "rgw_user_usage_log_add()");
 
454
 
 
455
  bufferlist::iterator in_iter = in->begin();
 
456
  rgw_cls_usage_log_add_op op;
 
457
 
 
458
  try {
 
459
    ::decode(op, in_iter);
 
460
  } catch (buffer::error& err) {
 
461
    CLS_LOG(1, "ERROR: rgw_user_usage_log_add(): failed to decode request\n");
 
462
    return -EINVAL;
 
463
  }
 
464
 
 
465
  rgw_usage_log_info& info = op.info;
 
466
  vector<rgw_usage_log_entry>::iterator iter;
 
467
 
 
468
  for (iter = info.entries.begin(); iter != info.entries.end(); ++iter) {
 
469
    rgw_usage_log_entry& entry = *iter;
 
470
    string key_by_time;
 
471
    usage_record_name_by_time(entry.epoch, entry.owner, entry.bucket, key_by_time);
 
472
 
 
473
    CLS_LOG(10, "rgw_user_usage_log_add user=%s bucket=%s\n", entry.owner.c_str(), entry.bucket.c_str());
 
474
 
 
475
    bufferlist record_bl;
 
476
    int ret = cls_cxx_map_get_val(hctx, key_by_time, &record_bl);
 
477
    if (ret < 0 && ret != -ENOENT) {
 
478
      CLS_LOG(1, "ERROR: rgw_user_usage_log_add(): cls_cxx_map_read_key returned %d\n", ret);
 
479
      return -EINVAL;
 
480
    }
 
481
    if (ret >= 0) {
 
482
      rgw_usage_log_entry e;
 
483
      ret = usage_record_decode(record_bl, e);
 
484
      if (ret < 0)
 
485
        return ret;
 
486
      CLS_LOG(10, "rgw_user_usage_log_add aggregating existing bucket\n");
 
487
      entry.aggregate(e);
 
488
    }
 
489
 
 
490
    bufferlist new_record_bl;
 
491
    ::encode(entry, new_record_bl);
 
492
    ret = cls_cxx_map_set_val(hctx, key_by_time, &new_record_bl);
 
493
    if (ret < 0)
 
494
      return ret;
 
495
 
 
496
    string key_by_user;
 
497
    usage_record_name_by_user(entry.owner, entry.epoch, entry.bucket, key_by_user);
 
498
    ret = cls_cxx_map_set_val(hctx, key_by_user, &new_record_bl);
 
499
    if (ret < 0)
 
500
      return ret;
 
501
  }
 
502
 
 
503
  return 0;
 
504
}
 
505
 
 
506
static int usage_iterate_range(cls_method_context_t hctx, uint64_t start, uint64_t end,
 
507
                            string& user, string& key_iter, uint32_t max_entries, bool *truncated,
 
508
                            int (*cb)(cls_method_context_t, const string&, rgw_usage_log_entry&, void *),
 
509
                            void *param)
 
510
{
 
511
  CLS_LOG(10, "usage_iterate_range");
 
512
 
 
513
  map<string, bufferlist> keys;
 
514
#define NUM_KEYS 32
 
515
  string filter_prefix;
 
516
  string start_key, end_key;
 
517
  bool by_user = !user.empty();
 
518
  uint32_t i = 0;
 
519
  string user_key;
 
520
 
 
521
  if (truncated)
 
522
    *truncated = false;
 
523
 
 
524
  if (!by_user) {
 
525
    usage_record_prefix_by_time(end, end_key);
 
526
  } else {
 
527
    user_key = user;
 
528
    user_key.append("_");
 
529
  }
 
530
 
 
531
  if (key_iter.empty()) {
 
532
    if (by_user) {
 
533
      start_key = user;
 
534
    } else {
 
535
      usage_record_prefix_by_time(start, start_key);
 
536
    }
 
537
  } else {
 
538
    start_key = key_iter;
 
539
  }
 
540
 
 
541
  do {
 
542
    int ret = cls_cxx_map_get_vals(hctx, start_key, filter_prefix, NUM_KEYS, &keys);
 
543
    if (ret < 0)
 
544
      return ret;
 
545
 
 
546
 
 
547
    map<string, bufferlist>::iterator iter = keys.begin();
 
548
    if (iter == keys.end())
 
549
      break;
 
550
 
 
551
    for (; iter != keys.end(); ++iter) {
 
552
      const string& key = iter->first;
 
553
      rgw_usage_log_entry e;
 
554
 
 
555
      if (!by_user && key.compare(end_key) >= 0)
 
556
        return 0;
 
557
 
 
558
      if (by_user && key.compare(0, user_key.size(), user_key) != 0)
 
559
        return 0;
 
560
 
 
561
      ret = usage_record_decode(iter->second, e);
 
562
      if (ret < 0)
 
563
        return ret;
 
564
 
 
565
      if (e.epoch < start)
 
566
        continue;
 
567
 
 
568
      /* keys are sorted by epoch, so once we're past end we're done */
 
569
      if (e.epoch >= end)
 
570
        return 0;
 
571
 
 
572
      ret = cb(hctx, key, e, param);
 
573
      if (ret < 0)
 
574
        return ret;
 
575
 
 
576
 
 
577
      i++;
 
578
      if (max_entries && (i > max_entries)) {
 
579
        *truncated = true;
 
580
        key_iter = key;
 
581
        return 0;
 
582
      }
 
583
    }
 
584
    iter--;
 
585
    start_key = iter->first;
 
586
  } while (true);
 
587
  return 0;
 
588
}
 
589
 
 
590
static int usage_log_read_cb(cls_method_context_t hctx, const string& key, rgw_usage_log_entry& entry, void *param)
 
591
{
 
592
  map<rgw_user_bucket, rgw_usage_log_entry> *usage = (map<rgw_user_bucket, rgw_usage_log_entry> *)param;
 
593
  rgw_user_bucket ub(entry.owner, entry.bucket);
 
594
  rgw_usage_log_entry& le = (*usage)[ub];
 
595
  le.aggregate(entry);
 
596
 
 
597
  return 0;
 
598
}
 
599
 
 
600
int rgw_user_usage_log_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
 
601
{
 
602
  CLS_LOG(10, "rgw_user_usage_log_read()");
 
603
 
 
604
  bufferlist::iterator in_iter = in->begin();
 
605
  rgw_cls_usage_log_read_op op;
 
606
 
 
607
  try {
 
608
    ::decode(op, in_iter);
 
609
  } catch (buffer::error& err) {
 
610
    CLS_LOG(1, "ERROR: rgw_user_usage_log_read(): failed to decode request\n");
 
611
    return -EINVAL;
 
612
  }
 
613
 
 
614
  rgw_cls_usage_log_read_ret ret_info;
 
615
  map<rgw_user_bucket, rgw_usage_log_entry> *usage = &ret_info.usage;
 
616
  string iter = op.iter;
 
617
#define MAX_ENTRIES 1000
 
618
  uint32_t max_entries = (op.max_entries ? op.max_entries : MAX_ENTRIES);
 
619
  int ret = usage_iterate_range(hctx, op.start_epoch, op.end_epoch, op.owner, iter, max_entries, &ret_info.truncated, usage_log_read_cb, (void *)usage);
 
620
  if (ret < 0)
 
621
    return ret;
 
622
 
 
623
  if (ret_info.truncated)
 
624
    ret_info.next_iter = iter;
 
625
 
 
626
  ::encode(ret_info, *out);
 
627
  return 0;
 
628
}
 
629
 
 
630
static int usage_log_trim_cb(cls_method_context_t hctx, const string& key, rgw_usage_log_entry& entry, void *param)
 
631
{
 
632
  string key_by_time;
 
633
  string key_by_user;
 
634
 
 
635
  usage_record_name_by_time(entry.epoch, entry.owner, entry.bucket, key_by_time);
 
636
  usage_record_name_by_user(entry.owner, entry.epoch, entry.bucket, key_by_user);
 
637
 
 
638
  int ret = cls_cxx_map_remove_key(hctx, key_by_time);
 
639
  if (ret < 0)
 
640
    return ret;
 
641
 
 
642
  return cls_cxx_map_remove_key(hctx, key_by_user);
 
643
}
 
644
 
 
645
int rgw_user_usage_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
 
646
{
 
647
  CLS_LOG(10, "rgw_user_usage_log_trim()");
 
648
 
 
649
  /* only continue if object exists! */
 
650
  int ret = cls_cxx_stat(hctx, NULL, NULL);
 
651
  if (ret < 0)
 
652
    return ret;
 
653
 
 
654
  bufferlist::iterator in_iter = in->begin();
 
655
  rgw_cls_usage_log_trim_op op;
 
656
 
 
657
  try {
 
658
    ::decode(op, in_iter);
 
659
  } catch (buffer::error& err) {
 
660
    CLS_LOG(1, "ERROR: rgw_user_log_usage_log_trim(): failed to decode request\n");
 
661
    return -EINVAL;
 
662
  }
 
663
 
 
664
  string iter;
 
665
  ret = usage_iterate_range(hctx, op.start_epoch, op.end_epoch, op.user, iter, 0, NULL, usage_log_trim_cb, NULL);
 
666
  if (ret < 0)
 
667
    return ret;
 
668
 
 
669
  return 0;
 
670
}
 
671
 
411
672
void __cls_init()
412
673
{
413
 
  CLS_LOG("Loaded rgw class!");
 
674
  CLS_LOG(1, "Loaded rgw class!");
414
675
 
415
676
  cls_register("rgw", &h_class);
416
677
  cls_register_cxx_method(h_class, "bucket_init_index", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_bucket_init_index, &h_rgw_bucket_init_index);
418
679
  cls_register_cxx_method(h_class, "bucket_prepare_op", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_bucket_prepare_op, &h_rgw_bucket_prepare_op);
419
680
  cls_register_cxx_method(h_class, "bucket_complete_op", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_bucket_complete_op, &h_rgw_bucket_complete_op);
420
681
  cls_register_cxx_method(h_class, "dir_suggest_changes", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_dir_suggest_changes, &h_rgw_dir_suggest_changes);
 
682
  cls_register_cxx_method(h_class, "user_usage_log_add", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_user_usage_log_add, &h_rgw_user_usage_log_add);
 
683
  cls_register_cxx_method(h_class, "user_usage_log_read", CLS_METHOD_RD | CLS_METHOD_PUBLIC, rgw_user_usage_log_read, &h_rgw_user_usage_log_read);
 
684
  cls_register_cxx_method(h_class, "user_usage_log_trim", CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, rgw_user_usage_log_trim, &h_rgw_user_usage_log_trim);
421
685
 
422
686
  return;
423
687
}