2 * 2008+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
18 #include <sys/types.h>
20 #include <sys/socket.h>
31 #include "elliptics.h"
33 #include "elliptics/packet.h"
34 #include "elliptics/interface.h"
36 #define dnet_map_log(n, mask, fmt, a...) do { if ((n)) dnet_log((n), mask, fmt, ##a); else fprintf(stderr, fmt, ##a); } while (0)
38 static int dnet_update_ts_metadata_raw(struct dnet_meta_container
*mc
, uint64_t flags_set
, uint64_t flags_clear
)
41 void *data
= mc
->data
;
42 uint32_t size
= mc
->size
;
43 struct dnet_meta_update
*mu
;
46 if (size
< sizeof(struct dnet_meta
)) {
50 m
= *(struct dnet_meta
*)data
;
51 dnet_convert_meta(&m
);
53 if (m
.size
+ sizeof(struct dnet_meta
) > size
) {
57 if (m
.type
== DNET_META_UPDATE
) {
58 mu
= (struct dnet_meta_update
*)(data
+ sizeof(struct dnet_meta
));
60 dnet_convert_meta_update(mu
);
62 dnet_current_time(&mu
->tm
);
63 mu
->flags
|= flags_set
;
64 mu
->flags
&= ~flags_clear
;
66 dnet_convert_meta_update(mu
);
69 data
+= m
.size
+ sizeof(struct dnet_meta
);
70 size
-= m
.size
+ sizeof(struct dnet_meta
);
76 void dnet_create_meta_update(struct dnet_meta
*m
, struct timespec
*ts
, uint64_t flags_set
, uint64_t flags_clear
)
78 struct dnet_meta_update
*mu
= (struct dnet_meta_update
*)m
->data
;
80 m
->size
= sizeof(struct dnet_meta_update
);
81 m
->type
= DNET_META_UPDATE
;
84 dnet_current_time(&mu
->tm
);
86 mu
->tm
.tsec
= ts
->tv_sec
;
87 mu
->tm
.tnsec
= ts
->tv_nsec
;
91 mu
->flags
|= flags_set
;
92 mu
->flags
&= ~flags_clear
;
94 dnet_convert_meta_update(mu
);
98 int dnet_update_ts_metadata(struct eblob_backend
*b
, struct dnet_raw_id
*id
, uint64_t flags_set
, uint64_t flags_clear
)
101 struct dnet_meta_container mc
;
104 memset(&mc
, 0, sizeof(struct dnet_meta_container
));
106 err
= dnet_db_read_raw(b
, id
, &mc
.data
);
108 m
= malloc(sizeof(struct dnet_meta
) + sizeof(struct dnet_meta_update
));
113 dnet_create_meta_update(m
, NULL
, flags_set
, flags_clear
);
116 mc
.size
= sizeof(struct dnet_meta_update
) + sizeof(struct dnet_meta
);
118 err
= dnet_update_ts_metadata_raw(&mc
, flags_set
, flags_clear
);
120 /* broken metadata, rewrite it */
121 if (err
!= -ENOENT
) {
128 mc
.data
= realloc(mc
.data
, mc
.size
+ sizeof(struct dnet_meta
) + sizeof(struct dnet_meta_update
));
134 m
= mc
.data
+ mc
.size
;
135 mc
.size
+= sizeof(struct dnet_meta
) + sizeof(struct dnet_meta_update
);
137 dnet_create_meta_update(m
, NULL
, flags_set
, flags_clear
);
141 err
= dnet_db_write_raw(b
, id
, mc
.data
, mc
.size
);
152 struct dnet_meta_update
*dnet_get_meta_update(struct dnet_node
*n
, struct dnet_meta_container
*mc
,
153 struct dnet_meta_update
*meta_update
)
156 void *data
= mc
->data
;
157 uint32_t size
= mc
->size
;
158 struct dnet_meta_update
*mu
;
162 if (size
< sizeof(struct dnet_meta
)) {
163 dnet_log(n
, DNET_LOG_ERROR
, "Metadata size %u is too small, min %zu, searching for type 0x%x.\n",
164 size
, sizeof(struct dnet_meta
), DNET_META_UPDATE
);
168 m
= *(struct dnet_meta
*)data
;
169 dnet_convert_meta(&m
);
171 if (m
.size
+ sizeof(struct dnet_meta
) > size
) {
172 dnet_log(n
, DNET_LOG_ERROR
, "Metadata entry broken: entry size %u, type: 0x%x, struct size: %zu, "
173 "total size left: %u, searching for type: 0x%x.\n",
174 m
.size
, m
.type
, sizeof(struct dnet_meta
), size
, DNET_META_UPDATE
);
178 if (m
.type
== DNET_META_UPDATE
) {
179 mu
= (struct dnet_meta_update
*)(data
+ sizeof(struct dnet_meta
));
181 num
= m
.size
/ sizeof(struct dnet_meta_update
);
184 memcpy(meta_update
, &mu
[0], sizeof(struct dnet_meta_update
));
185 dnet_convert_meta_update(meta_update
);
191 data
+= m
.size
+ sizeof(struct dnet_meta
);
192 size
-= m
.size
+ sizeof(struct dnet_meta
);
197 struct dnet_meta
*dnet_meta_search(struct dnet_node
*n
, struct dnet_meta_container
*mc
, uint32_t type
)
199 void *data
= mc
->data
;
200 uint32_t size
= mc
->size
;
201 struct dnet_meta m
, *found
= NULL
;
204 if (size
< sizeof(struct dnet_meta
)) {
205 dnet_map_log(n
, DNET_LOG_ERROR
, "Metadata size %u is too small, min %zu, searching for type 0x%x.\n",
206 size
, sizeof(struct dnet_meta
), type
);
210 m
= *(struct dnet_meta
*)data
;
211 dnet_convert_meta(&m
);
213 if (m
.size
+ sizeof(struct dnet_meta
) > size
) {
214 dnet_map_log(n
, DNET_LOG_ERROR
, "Metadata entry broken: entry size %u, type: 0x%x, struct size: %zu, "
215 "total size left: %u, searching for type: 0x%x.\n",
216 m
.size
, m
.type
, sizeof(struct dnet_meta
), size
, type
);
220 if (m
.type
== type
) {
225 data
+= m
.size
+ sizeof(struct dnet_meta
);
226 size
-= m
.size
+ sizeof(struct dnet_meta
);
232 void dnet_convert_metadata(struct dnet_node
*n __unused
, void *data
, int size
)
240 ptr
+= sizeof(struct dnet_meta
) + m
->size
;
241 size
-= sizeof(struct dnet_meta
) + m
->size
;
243 dnet_convert_meta(m
);
247 int dnet_write_metadata(struct dnet_node
*n
, struct dnet_meta_container
*mc
, int convert
, uint64_t cflags
)
249 struct dnet_io_control ctl
;
253 if (n
->flags
& DNET_CFG_NO_META
)
257 dnet_convert_metadata(n
, mc
->data
, mc
->size
);
259 memset(&ctl
, 0, sizeof(ctl
));
264 ctl
.io
.size
= mc
->size
;
265 ctl
.io
.flags
= DNET_IO_FLAGS_META
;
268 memcpy(&ctl
.id
, &mc
->id
, sizeof(struct dnet_id
));
269 ctl
.id
.type
= ctl
.io
.type
= EBLOB_TYPE_META
;
271 err
= dnet_write_data_wait(n
, &ctl
, &result
);
280 int dnet_create_write_metadata_strings(struct dnet_node
*n
, const void *remote
, unsigned int remote_len
,
281 struct dnet_id
*id
, struct timespec
*ts
, uint64_t cflags
)
283 struct dnet_metadata_control mc
;
288 pthread_mutex_lock(&n
->group_lock
);
289 group_num
= n
->group_num
;
290 groups
= alloca(group_num
* sizeof(int));
292 memcpy(groups
, n
->groups
, group_num
* sizeof(int));
293 pthread_mutex_unlock(&n
->group_lock
);
295 memset(&mc
, 0, sizeof(mc
));
299 mc
.group_num
= group_num
;
308 gettimeofday(&tv
, NULL
);
309 mc
.ts
.tv_sec
= tv
.tv_sec
;
310 mc
.ts
.tv_nsec
= tv
.tv_usec
* 1000;
313 err
= dnet_create_write_metadata(n
, &mc
);
315 dnet_log(n
, DNET_LOG_ERROR
, "%s: failed to write metadata: %d\n", dnet_dump_id(id
), err
);
321 int dnet_create_metadata(struct dnet_node
*n
, struct dnet_metadata_control
*ctl
, struct dnet_meta_container
*mc
)
323 struct dnet_meta_check_status
*c
;
325 int size
= 0, err
, nsize
= 0;
328 size
+= sizeof(struct dnet_meta_check_status
) + sizeof(struct dnet_meta
);
330 if (ctl
->obj
&& ctl
->len
)
331 size
+= ctl
->len
+ sizeof(struct dnet_meta
);
333 if (ctl
->groups
&& ctl
->group_num
)
334 size
+= ctl
->group_num
* sizeof(int) + sizeof(struct dnet_meta
);
336 size
+= sizeof(struct dnet_meta_update
) + sizeof(struct dnet_meta
);
338 ns
= dnet_node_get_ns(n
, &nsize
);
340 size
+= nsize
+ sizeof(struct dnet_meta
);
347 mc
->data
= malloc(size
);
352 memset(mc
->data
, 0, size
);
354 m
= (struct dnet_meta
*)(mc
->data
);
356 c
= (struct dnet_meta_check_status
*)m
->data
;
357 m
->size
= sizeof(struct dnet_meta_check_status
);
358 m
->type
= DNET_META_CHECK_STATUS
;
360 /* Check status is undefined for now, it will be filled during actual check */
361 memset(c
, 0, sizeof(struct dnet_meta_check_status
));
363 m
= (struct dnet_meta
*)(m
->data
+ m
->size
);
364 dnet_create_meta_update(m
, ctl
->ts
.tv_sec
? &ctl
->ts
: NULL
, 0, 0);
366 m
= (struct dnet_meta
*)(m
->data
+ m
->size
);
368 if (ctl
->obj
&& ctl
->len
) {
370 m
->type
= DNET_META_PARENT_OBJECT
;
371 memcpy(m
->data
, ctl
->obj
, ctl
->len
);
373 m
= (struct dnet_meta
*)(m
->data
+ m
->size
);
376 if (ctl
->groups
&& ctl
->group_num
) {
377 m
->size
= ctl
->group_num
* sizeof(int);
378 m
->type
= DNET_META_GROUPS
;
379 memcpy(m
->data
, ctl
->groups
, ctl
->group_num
* sizeof(int));
381 m
= (struct dnet_meta
*)(m
->data
+ m
->size
);
386 m
->type
= DNET_META_NAMESPACE
;
387 memcpy(m
->data
, ns
, nsize
);
389 m
= (struct dnet_meta
*)(m
->data
+ m
->size
);
393 memcpy(&mc
->id
, &ctl
->id
, sizeof(struct dnet_id
));
400 int dnet_create_write_metadata(struct dnet_node
*n
, struct dnet_metadata_control
*ctl
)
402 struct dnet_meta_container mc
;
405 memset(&mc
, 0, sizeof(struct dnet_meta_container
));
407 err
= dnet_create_metadata(n
, ctl
, &mc
);
411 err
= dnet_write_metadata(n
, &mc
, 1, ctl
->cflags
);
421 static char *dnet_meta_types
[__DNET_META_MAX
] = {
422 [DNET_META_PARENT_OBJECT
] = "DNET_META_PARENT_OBJECT",
423 [DNET_META_GROUPS
] = "DNET_META_GROUPS",
424 [DNET_META_CHECK_STATUS
] = "DNET_META_CHECK_STATUS",
425 [DNET_META_NAMESPACE
] = "DNET_META_NAMESPACE",
426 [DNET_META_UPDATE
] = "DNET_META_UPDATE",
427 [DNET_META_CHECKSUM
] = "DNET_META_CHECKSUM",
430 void dnet_meta_print(struct dnet_node
*n
, struct dnet_meta_container
*mc
)
441 dnet_log(n
, DNET_LOG_DATA
, "%s: size: %u\n", dnet_dump_id_len(&mc
->id
, DNET_ID_SIZE
), mc
->size
);
446 dnet_convert_meta(m
);
448 if (m
->type
>= __DNET_META_MAX
|| m
->type
< DNET_META_PARENT_OBJECT
) {
449 dnet_log(n
, DNET_LOG_ERROR
, "%s: incorrect meta type %d\n", dnet_dump_id(&mc
->id
), m
->type
);
453 if (m
->type
== DNET_META_PARENT_OBJECT
) {
454 char name
[m
->size
+ 1];
456 memcpy(name
, m
->data
, m
->size
);
457 name
[m
->size
] = '\0';
458 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, name: '%s'\n",
459 dnet_meta_types
[m
->type
], m
->type
, m
->size
, name
);
460 } else if (m
->type
== DNET_META_GROUPS
) {
461 int *groups
= (int *)m
->data
;
462 int gnum
= m
->size
/ sizeof(int);
463 char str
[gnum
* 36 + 1], *ptr
;
466 memset(str
, 0, sizeof(str
));
470 for (i
=0; i
<gnum
; ++i
) {
471 err
= snprintf(ptr
, rest
, "%d:", groups
[i
]);
482 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, groups: %s\n",
483 dnet_meta_types
[m
->type
], m
->type
, m
->size
, str
);
484 } else if (m
->type
== DNET_META_CHECK_STATUS
) {
485 struct dnet_meta_check_status
*s
= (struct dnet_meta_check_status
*)m
->data
;
487 dnet_convert_meta_check_status(s
);
489 localtime_r((time_t *)&s
->tm
.tsec
, &tm
);
490 strftime(tstr
, sizeof(tstr
), "%F %R:%S %Z", &tm
);
492 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, check status: %d, ts: %s: %lld.%lld\n",
493 dnet_meta_types
[m
->type
],
494 m
->type
, m
->size
, s
->status
, tstr
,
495 (unsigned long long)s
->tm
.tsec
,
496 (unsigned long long)s
->tm
.tnsec
);
497 } else if (m
->type
== DNET_META_UPDATE
) {
498 struct dnet_meta_update
*mu
= (struct dnet_meta_update
*)m
->data
;
500 dnet_convert_meta_update(mu
);
502 localtime_r((time_t *)&mu
->tm
.tsec
, &tm
);
503 strftime(tstr
, sizeof(tstr
), "%F %R:%S %Z", &tm
);
505 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, flags: %llx, ts: %s %lld.%lld\n",
506 dnet_meta_types
[m
->type
], m
->type
, m
->size
,
507 (unsigned long long)mu
->flags
, tstr
,
508 (unsigned long long)mu
->tm
.tsec
, (unsigned long long)mu
->tm
.tnsec
);
509 } else if (m
->type
== DNET_META_NAMESPACE
) {
510 char str
[m
->size
+ 1];
511 memcpy(str
, m
->data
, m
->size
);
514 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, namespace: %s\n",
515 dnet_meta_types
[m
->type
], m
->type
, m
->size
, str
);
516 } else if (m
->type
== DNET_META_CHECKSUM
) {
517 struct dnet_meta_checksum
*cs
= (struct dnet_meta_checksum
*)m
->data
;
518 char str
[2*DNET_CSUM_SIZE
+1];
520 localtime_r((time_t *)&cs
->tm
.tsec
, &tm
);
521 strftime(tstr
, sizeof(tstr
), "%F %R:%S %Z", &tm
);
523 dnet_dump_id_len_raw(cs
->checksum
, DNET_CSUM_SIZE
, str
);
524 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u, csum: %s, ts: %s %lld.%lld\n",
525 dnet_meta_types
[m
->type
], m
->type
, m
->size
, str
, tstr
,
526 (unsigned long long)cs
->tm
.tsec
, (unsigned long long)cs
->tm
.tnsec
);
528 dnet_log(n
, DNET_LOG_DATA
, "%s: type: %u, size: %u\n",
529 dnet_meta_types
[m
->type
], m
->type
, m
->size
);
532 data
+= m
->size
+ sizeof(*m
);
533 size
-= m
->size
+ sizeof(*m
);
537 int dnet_read_meta(struct dnet_node
*n
, struct dnet_meta_container
*mc
,
538 const void *remote
, unsigned int remote_len
, struct dnet_id
*id
)
540 struct dnet_io_attr io
;
545 io
.flags
= DNET_IO_FLAGS_META
;
549 io
.start
= io
.num
= 0;
557 dnet_transform(n
, remote
, remote_len
, &raw
);
562 memcpy(io
.id
, id
->id
, DNET_ID_SIZE
);
563 memcpy(io
.parent
, id
->id
, DNET_ID_SIZE
);
565 data
= dnet_read_data_wait(n
, id
, &io
, 0, &err
);
569 memcpy(io
.id
, id
->id
, DNET_ID_SIZE
);
570 memcpy(io
.parent
, id
->id
, DNET_ID_SIZE
);
572 data
= dnet_read_data_wait_raw(n
, id
, &io
, DNET_CMD_READ
, 0, &err
);
576 io
.size
-= sizeof(struct dnet_io_attr
);
578 mc
->data
= malloc(io
.size
);
584 memcpy(mc
->data
, data
+ sizeof(struct dnet_io_attr
), io
.size
);
586 memcpy(&mc
->id
, id
, sizeof(struct dnet_id
));
596 int dnet_meta_update_check_status_raw(struct dnet_node
*n
, struct dnet_meta_container
*mc
)
598 struct dnet_meta
*m
= NULL
;
599 struct dnet_meta_check_status
*meta_check
;
602 m
= dnet_meta_search(n
, mc
, DNET_META_CHECK_STATUS
);
605 mc
->data
= realloc(mc
->data
, mc
->size
+ sizeof(struct dnet_meta
) + sizeof(struct dnet_meta_check_status
));
611 m
= mc
->data
+ mc
->size
;
612 mc
->size
+= sizeof(struct dnet_meta
) + sizeof(struct dnet_meta_check_status
);
614 m
->type
= DNET_META_CHECK_STATUS
;
615 m
->size
= sizeof(struct dnet_meta_check_status
);
616 dnet_convert_meta(m
);
619 meta_check
= (struct dnet_meta_check_status
*)m
->data
;
620 meta_check
->status
= 0;
622 dnet_current_time(&meta_check
->tm
);
624 dnet_convert_meta_check_status(meta_check
);
633 int dnet_meta_update_check_status(struct dnet_node
*n
, struct dnet_meta_container
*mc
)
635 struct dnet_raw_id id
;
638 err
= dnet_meta_update_check_status_raw(n
, mc
);
641 dnet_log(n
, DNET_LOG_ERROR
, "%s: failed to update DNET_META_CHECK_STATUS, err=%d\n",
642 dnet_dump_id(&mc
->id
), err
);
645 memcpy(&id
.id
, &mc
->id
.id
, DNET_ID_SIZE
);
646 err
= n
->cb
->meta_write(n
->cb
->command_private
, &id
, mc
->data
, mc
->size
);
648 dnet_log(n
, DNET_LOG_ERROR
, "%s: failed to write meta, err=%d\n",
649 dnet_dump_id(&mc
->id
), err
);