File: tail40.c

package info (click to toggle)
reiser4progs 1.2.2-1
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 5,904 kB
  • sloc: ansic: 34,331; sh: 4,251; makefile: 994
file content (462 lines) | stat: -rw-r--r-- 13,250 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/* Copyright (C) 2001-2005 by Hans Reiser, licensing governed by
   reiser4progs/COPYING.
   
   tail40.c -- reiser4 tail (formatting) item plugin. */

#include "tail40.h"
#include "tail40_repair.h"

#include <aux/aux.h>
#include <reiser4/plugin.h>
#include <plugin/item/body40/body40.h>

/* Returns tail length. */
uint32_t tail40_units(reiser4_place_t *place) {
	return place->len - place->off;
}

/* Returns key from tail at @place. */
errno_t tail40_fetch_key(reiser4_place_t *place, reiser4_key_t *key) {
	uint32_t pos;
	
	aal_assert("vpf-627", key != NULL);
	aal_assert("vpf-626", place != NULL);

	pos = place->pos.unit;
	return body40_get_key(place, pos, key, NULL);
}

/* Reads units from tail at @place into passed @hint. */
int64_t tail40_read_units(reiser4_place_t *place, trans_hint_t *hint) {
	uint32_t count;
	
	aal_assert("umka-1674", hint != NULL);
	aal_assert("umka-1673", place != NULL);
	aal_assert("vpf-1859", hint->specific != NULL);

	count = hint->count;

	/* Check if we read from the start of item. If so normilize position to
	   read from. Value MAX_UINT32 is used in libreiser4 for denoting that
	   we want to do something to whole item, that is from its start. */
	if (place->pos.unit == MAX_UINT32)
		place->pos.unit = 0;

	/* Calculating number of bytes, which can be actually read from this
	   tail item. It cannot be more than item length. */
	if (tail40_pos(place) + hint->count > place->len)
		count = place->len - tail40_pos(place);

	/* Copying data from tail body to hint. */
	aal_memcpy(hint->specific, place->body + tail40_pos(place), count);
	
	return count;
}

#ifndef ENABLE_MINIMAL
/* Estimates how many bytes in tree is needed to write @hint->count bytes of
   data. This function considers, that tail item is not expandable one. That is,
   tail will not be splitted at insert point, but will be rewritten instead. */
errno_t tail40_prep_write(reiser4_place_t *place, trans_hint_t *hint) {
	uint16_t space;
	
	aal_assert("umka-1836", hint != NULL);
	aal_assert("umka-2437", place != NULL);
	aal_assert("umka-3113", place->node != NULL);
	
	hint->overhead = place->off;
	
	/* Check if we want to create new tail item. If so, we say, that we need
	   @hint->count bytes in tree. Even if this is more than one node can
	   fit, it is okay, because write function will actually write only
	   amount of data which may fit into node at passed @place. */
	if (place->pos.unit == MAX_UINT32) {
		hint->len = hint->count;

		aal_memcpy(&hint->maxkey, &hint->offset, sizeof(hint->maxkey));
	} else {
		uint32_t right;
		uint64_t max_offset;

		aal_assert("umka-2284", place != NULL);

		/* Item already exists. We will rewrite some part of it and some
		   part have to be append. */
		right = place->len - tail40_pos(place);
		hint->len = right ? 0 : hint->count;
		
		/* Getting maximal real key. It will be needed to determine if
		   we insert data inside tail or behind it. */
		tail40_maxreal_key(place, &hint->maxkey);

		max_offset = objcall(&hint->maxkey, get_offset) + 1;
		objcall(&hint->maxkey, set_offset, max_offset);
	}

	/* Max possible item size. */
	space = objcall(place->node, maxspace);
	
	if (hint->len > (int32_t)(space - hint->overhead))
		hint->len = space - hint->overhead;
	
	return 0;
}

/* Rewrites tail from passed @place by data from @hint. */
int64_t tail40_write_units(reiser4_place_t *place, trans_hint_t *hint) {
	uint64_t ins_offset;
	uint64_t max_offset;
	uint32_t count;
	
	aal_assert("umka-1677", hint != NULL);
	aal_assert("umka-1678", place != NULL);

	hint->bytes = 0;
	count = hint->count;

	/* Check if we create new tail item. If so -- normalize insert pos. */
	if (place->pos.unit == MAX_UINT32)
		place->pos.unit = 0;

	/* Calculating actual amount of data to be written. */
	if (count + tail40_pos(place) > place->len)
		count = place->len - tail40_pos(place);

	/* Getting old max real offset. */
	max_offset = objcall(&hint->maxkey, get_offset);

	/* Getting insert offset. */
	ins_offset = objcall(&hint->offset, get_offset);
	
	/* Checking if we insert a hole. That is @hint->specific si null. If so,
	   then we write @count of zeros. Writing data from @hint->specific
	   otherwise. */
	if (hint->specific) {
		/* Copying data into @place. */
		aal_memcpy(place->body + tail40_pos(place), 
			   hint->specific, count);
	} else {
		/* Making hole @count of size. */
		aal_memset(place->body + tail40_pos(place), 
			   0, count);
	}

	/* Updating item key if pos is zero, that is start of item. 
	   FIXME: this seems to do nothing. */
	if (place->pos.unit == 0)
		body40_get_key(place, 0, &place->key, NULL);

	/* Bytes are added if we wrote something behind of item size. */
	if (ins_offset + count > max_offset)
		hint->bytes = ins_offset + count - max_offset;
	
	place_mkdirty(place);
	return count;
}

/* Return max real key inside tail at @place. */
errno_t tail40_maxreal_key(reiser4_place_t *place, reiser4_key_t *key) {
	aal_assert("vpf-442", place != NULL);
	aal_assert("vpf-443", key != NULL);
	return body40_maxreal_key(place, key, NULL);
}
#endif

/* Return max possible key iside tail at @place. */
errno_t tail40_maxposs_key(reiser4_place_t *place, reiser4_key_t *key) {
	aal_assert("umka-1209", place != NULL);
	aal_assert("umka-1210", key != NULL);
	return body40_maxposs_key(place, key);
}

/* Makes lookup of @key inside tail at @place. */
lookup_t tail40_lookup(reiser4_place_t *place,
		       lookup_hint_t *hint,
		       lookup_bias_t bias)
{
	uint32_t units;
	uint64_t offset;
	uint64_t wanted;

	aal_assert("umka-1229", hint != NULL);
	aal_assert("umka-1228", place != NULL);

	units = tail40_units(place);	
	offset = objcall(&place->key, get_offset);
	wanted = objcall(hint->key, get_offset);

	/* Check if needed key is inside this tail. */
	if (wanted >= offset && wanted < offset + units) {
		place->pos.unit = wanted - offset;
		return PRESENT;
	}

	place->pos.unit = units;
	return (bias == FIND_CONV ? PRESENT : ABSENT);
}

#ifndef ENABLE_MINIMAL
/* FIXME: *_place->off is not properly handled here. */
/* Estimates how many bytes may be shifted from @stc_place to @dst_place. */
errno_t tail40_prep_shift(reiser4_place_t *src_place,
			  reiser4_place_t *dst_place,
			  shift_hint_t *hint)
{
	int check_point;
	uint32_t space;
	uint32_t overhead;

	aal_assert("umka-2279", hint != NULL);
	aal_assert("umka-1664", src_place != NULL);

	check_point = (src_place->pos.item == hint->pos.item &&
		       hint->pos.unit != MAX_UINT32);

	space = hint->units_bytes;
	
	/* If a new item is being created, substract the overhead. */
	overhead = hint->create ? src_place->off : 0;
	
	if (space <= overhead) {
		hint->units_bytes = hint->units_number = 0;
		return 0;
	}

	space -= overhead;
	
	/* Check if this is left shift. */
	if (hint->control & SF_ALLOW_LEFT) {
		/* Check if should take into account inert point from @hint. */
		if (hint->control & SF_UPDATE_POINT && check_point) {
			/* Correcting @hint->rest. It should contain number of
			   bytes we realy can shift. */
			if (space > hint->pos.unit)
				space = hint->pos.unit;

			hint->pos.unit -= space;

			/* Moving insert point to @dst_place. */
			if (hint->pos.unit == 0 &&
			    hint->control & SF_MOVE_POINT)
			{
				hint->result |= SF_MOVE_POINT;

				hint->pos.unit = space +
					(dst_place ? dst_place->len - 
					 dst_place->off : 0);
			}
		} else {
			if (space + src_place->off > src_place->len)
				space = src_place->len - src_place->off;
		}
	} else {
		uint32_t right;

		/* Check if should take into account insert point. */
		if (hint->control & SF_UPDATE_POINT && check_point) {
			/* Is insert point inside item? */
			if (hint->pos.unit + src_place->off < src_place->len) {
				right = src_place->len - hint->pos.unit - 
					src_place->off;

				/* Insert point inside item and we can move
				   something. */
				if (space > right)
					space = right;

				/* If all @right units are shifted, update the 
				   point if needed. */
				if ((space == right) && 
				    (hint->control & SF_MOVE_POINT))
				{
					hint->result |= SF_MOVE_POINT;
					hint->pos.unit = 0;
				}
			} else {
				/* Updating insert point to first position in
				   neighbour item. */
				if (hint->control & SF_MOVE_POINT) {
					hint->result |= SF_MOVE_POINT;
					hint->pos.unit = 0;
				}

				space = 0;
			}
		} else {
			if (space + src_place->off > src_place->len)
				space = src_place->len - src_place->off;
		}
	}

	hint->units_bytes = space + overhead;
	hint->units_number = space;
	return 0;
}

/* Copy @count of units from @src_place at src_pos to @dst_place and
   @dst_pos. This function is used in balancing code. */
errno_t tail40_copy(reiser4_place_t *dst_place, uint32_t dst_pos,
		    reiser4_place_t *src_place, uint32_t src_pos,
		    uint32_t count)
{
	aal_assert("umka-2075", dst_place != NULL);
	aal_assert("umka-2076", src_place != NULL);

	if (count > 0) {
		aal_memcpy(dst_place->body + dst_pos + dst_place->off,
			   src_place->body + src_pos + src_place->off, count);

		place_mkdirty(dst_place);
	}
	
	return 0;
}

/* Expand tail at @place and @pos by @count bytes. Used in balancing code
   pathes. */
uint32_t tail40_expand(reiser4_place_t *place, uint32_t pos, uint32_t count) {
	uint32_t size;
	
	aal_assert("vpf-1559", place->len >= pos + count + place->off);
	
	size = place->len - pos - place->off - count;
	
	if (size && count) {
		aal_memmove(place->body + place->off + pos + count,
			    place->body + place->off + pos, size);

		place_mkdirty(place);
	}

	return 0;
}

/* Shrink tail at @place and @pos by @count bytes. Used in balancing code
   pathes. */
static uint32_t tail40_shrink(reiser4_place_t *place, uint32_t pos,
			      uint32_t count, uint32_t len)
{
	uint32_t size;
	
	aal_assert("vpf-1764", place->len >= pos + count + place->off);
	
	size = place->len - pos - place->off - count;
	
	if (size && count) { 
		aal_memmove(place->body + pos + place->off,
			    place->body + pos + place->off + count, size);
		
		place_mkdirty(place);
	}

	return 0;
}

/* Shift some number of units from @src_place to @dst_place. All actions are
   performed with keeping in mind passed @hint. */
errno_t tail40_shift_units(reiser4_place_t *src_place,
			   reiser4_place_t *dst_place,
			   shift_hint_t *hint)
{
	uint32_t pos;
	uint64_t offset;
	
	aal_assert("umka-1665", src_place != NULL);
	aal_assert("umka-1666", dst_place != NULL);
	aal_assert("umka-1667", hint != NULL);

	if (hint->create)
		hint->units_bytes -= src_place->off;
	
	/* Check if this is left shift. */
	if (hint->control & SF_ALLOW_LEFT) {
		pos = dst_place->len - dst_place->off - hint->units_number;
		
		/* Expanding tail item at @dst_place by @hint->units_number
		   value. It is that, prep_shift() has prepared for us. */
		tail40_expand(dst_place, pos, hint->units_number);

		/* Copy @hint->units_bytes units from @src_place to @dst_place
		   at @dst_place->len position. */
		tail40_copy(dst_place, pos, src_place, 0,
			    hint->units_bytes);

		/* Shrink @src_place at 0 position by @hint->rest bytes, that is
		   by number of bytes we have just moved to @dst_place. */
		tail40_shrink(src_place, 0, hint->units_number,
			      hint->units_bytes);

		/* Updating @place->key in order to maintain consistency of left
		   delimiting keys. */
		offset = objcall(&src_place->key, get_offset);

		objcall(&src_place->key, set_offset, 
			offset + hint->units_bytes);
	} else {
		/* Right shift. Expanding @dst_place at 0 pos. */
		tail40_expand(dst_place, 0, hint->units_number);

		/* Copying data and removing it from source. */
		pos = src_place->len - src_place->off - hint->units_number;
		
		tail40_copy(dst_place, 0, src_place, pos,
			    hint->units_bytes);
		
		tail40_shrink(src_place, pos, hint->units_number,
			      hint->units_bytes);

		/* Updating place key. */
		offset = objcall(&dst_place->key, get_offset);
		
		objcall(&dst_place->key, set_offset, 
			offset - hint->units_bytes);
	}
	
	return 0;
}

/* Removes some number of units from tail at @place based on @hint. This is used
   in trunc_flow() code path. That is in tail convertion code and in object
   truncate() functions. */
int64_t tail40_trunc_units(reiser4_place_t *place, trans_hint_t *hint) {
	uint64_t count;

	aal_assert("umka-2480", hint != NULL);
	aal_assert("umka-2479", place != NULL);

	/* Correcting position. */
	if (place->pos.unit == MAX_UINT32)
		place->pos.unit = 0;

	/* Correcting count. */
	count = hint->count;
	
	if (tail40_pos(place) + count > place->len)
		count = place->len - tail40_pos(place);

	/* Taking care about rest of tail */
	if (tail40_pos(place) + count < place->len) {
		aal_memmove(place->body + tail40_pos(place),
			    place->body + tail40_pos(place) + count,
			    place->len - (tail40_pos(place) + count));
	}

	/* Updating key if it is needed. */
	if (place->pos.unit == 0 && tail40_pos(place) + count < place->len) {
		body40_get_key(place, place->pos.unit + count,
			       &place->key, NULL);
	}
	
	hint->overhead = (count == place->len - place->off) ? place->off : 0;
	hint->len = count;
	hint->bytes = count;
	
	return count;
}

/* Returns item size in bytes */
uint64_t tail40_size(reiser4_place_t *place) {
	aal_assert("vpf-1210", place != NULL);
	return place->len - place->off;
}
#endif