1 /* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
5 #if !defined(__REISER4_FLUSH_H__)
6 #define __REISER4_FLUSH_H__
8 #include "plugin/cluster.h"
10 /* The flush_scan data structure maintains the state of an in-progress
11 flush-scan on a single level of the tree. A flush-scan is used for counting
12 the number of adjacent nodes to flush, which is used to determine whether we
13 should relocate, and it is also used to find a starting point for flush. A
14 flush-scan object can scan in both right and left directions via the
15 scan_left() and scan_right() interfaces. The right- and left-variations are
16 similar but perform different functions. When scanning left we (optionally
17 perform rapid scanning and then) longterm-lock the endpoint node. When
18 scanning right we are simply counting the number of adjacent, dirty nodes. */
21 /* The current number of nodes scanned on this level. */
24 /* There may be a maximum number of nodes for a scan on any single
25 level. When going leftward, max_count is determined by
26 FLUSH_SCAN_MAXNODES (see reiser4.h) */
29 /* Direction: Set to one of the sideof enumeration:
30 { LEFT_SIDE, RIGHT_SIDE }. */
33 /* Initially @stop is set to false then set true once some condition
34 stops the search (e.g., we found a clean node before reaching
35 max_count or we found a node belonging to another atom). */
38 /* The current scan position. If @node is non-NULL then its reference
39 count has been incremented to reflect this reference. */
42 /* A handle for zload/zrelse of current scan position node. */
45 /* During left-scan, if the final position (a.k.a. endpoint node) is
46 formatted the node is locked using this lock handle. The endpoint
47 needs to be locked for transfer to the flush_position object after
49 lock_handle node_lock
;
51 /* When the position is unformatted, its parent, coordinate, and parent
52 zload/zrelse handle. */
53 lock_handle parent_lock
;
55 load_count parent_load
;
57 /* The block allocator preceder hint. Sometimes flush_scan determines
58 what the preceder is and if so it sets it here, after which it is
59 copied into the flush_position. Otherwise, the preceder is computed
61 reiser4_block_nr preceder_blk
;
64 struct convert_item_info
{
65 dc_item_stat d_cur
; /* disk cluster state of the current item */
66 dc_item_stat d_next
; /* disk cluster state of the next slum item */
67 int cluster_shift
; /* disk cluster shift */
68 flow_t flow
; /* disk cluster data */
72 int count
; /* for squalloc terminating */
73 item_plugin
*iplug
; /* current item plugin */
74 struct convert_item_info
*itm
; /* current item info */
75 struct cluster_handle clust
; /* transform cluster */
78 typedef enum flush_position_state
{
79 POS_INVALID
, /* Invalid or stopped pos, do not continue slum
81 POS_ON_LEAF
, /* pos points to already prepped, locked
82 * formatted node at leaf level */
83 POS_ON_EPOINT
, /* pos keeps a lock on twig level, "coord" field
84 * is used to traverse unformatted nodes */
85 POS_TO_LEAF
, /* pos is being moved to leaf level */
86 POS_TO_TWIG
, /* pos is being moved to twig level */
87 POS_END_OF_TWIG
, /* special case of POS_ON_TWIG, when coord is
88 * after rightmost unit of the current twig */
89 POS_ON_INTERNAL
/* same as POS_ON_LEAF, but points to internal
93 /* An encapsulation of the current flush point and all the parameters that are
94 passed through the entire squeeze-and-allocate stage of the flush routine.
95 A single flush_position object is constructed after left- and right-scanning
97 struct flush_position
{
98 flushpos_state_t state
;
100 coord_t coord
; /* coord to traverse unformatted nodes */
101 lock_handle lock
; /* current lock we hold */
102 load_count load
; /* load status for current locked formatted node
104 jnode
*child
; /* for passing a reference to unformatted child
105 * across pos state changes */
107 reiser4_blocknr_hint preceder
; /* The flush 'hint' state. */
108 int leaf_relocate
; /* True if enough leaf-level nodes were
109 * found to suggest a relocate policy. */
110 int alloc_cnt
; /* The number of nodes allocated during squeeze
112 int prep_or_free_cnt
; /* The number of nodes prepared for write
113 (allocate) or squeezed and freed. */
115 long *nr_written
; /* number of nodes submitted to disk */
116 int flags
; /* a copy of jnode_flush flags argument */
118 znode
*prev_twig
; /* previous parent pointer value, used to catch
119 * processing of new twig node */
120 struct convert_info
*sq
; /* convert info */
122 unsigned long pos_in_unit
; /* for extents only. Position
123 within an extent unit of first
125 long nr_to_write
; /* number of unformatted nodes to handle on
129 static inline int item_convert_count(flush_pos_t
*pos
)
131 return pos
->sq
->count
;
133 static inline void inc_item_convert_count(flush_pos_t
*pos
)
137 static inline void set_item_convert_count(flush_pos_t
*pos
, int count
)
139 pos
->sq
->count
= count
;
141 static inline item_plugin
*item_convert_plug(flush_pos_t
*pos
)
143 return pos
->sq
->iplug
;
146 static inline struct convert_info
*convert_data(flush_pos_t
*pos
)
151 static inline struct convert_item_info
*item_convert_data(flush_pos_t
*pos
)
153 assert("edward-955", convert_data(pos
));
157 static inline struct tfm_cluster
*tfm_cluster_sq(flush_pos_t
*pos
)
159 return &pos
->sq
->clust
.tc
;
162 static inline struct tfm_stream
*tfm_stream_sq(flush_pos_t
*pos
,
165 assert("edward-854", pos
->sq
!= NULL
);
166 return get_tfm_stream(tfm_cluster_sq(pos
), id
);
169 static inline int chaining_data_present(flush_pos_t
*pos
)
171 return convert_data(pos
) && item_convert_data(pos
);
174 /* Returns true if next node contains next item of the disk cluster
175 so item convert data should be moved to the right slum neighbor.
177 static inline int should_chain_next_node(flush_pos_t
*pos
)
181 assert("edward-1007", chaining_data_present(pos
));
183 switch (item_convert_data(pos
)->d_next
) {
184 case DC_CHAINED_ITEM
:
187 case DC_AFTER_CLUSTER
:
190 impossible("edward-1009", "bad state of next slum item");
195 /* update item state in a disk cluster to assign conversion mode */
197 move_chaining_data(flush_pos_t
*pos
, int this_node
/* where is next item */)
200 assert("edward-1010", chaining_data_present(pos
));
202 if (this_node
== 0) {
203 /* next item is on the right neighbor */
204 assert("edward-1011",
205 item_convert_data(pos
)->d_cur
== DC_FIRST_ITEM
||
206 item_convert_data(pos
)->d_cur
== DC_CHAINED_ITEM
);
207 assert("edward-1012",
208 item_convert_data(pos
)->d_next
== DC_CHAINED_ITEM
);
210 item_convert_data(pos
)->d_cur
= DC_CHAINED_ITEM
;
211 item_convert_data(pos
)->d_next
= DC_INVALID_STATE
;
213 /* next item is on the same node */
214 assert("edward-1013",
215 item_convert_data(pos
)->d_cur
== DC_FIRST_ITEM
||
216 item_convert_data(pos
)->d_cur
== DC_CHAINED_ITEM
);
217 assert("edward-1227",
218 item_convert_data(pos
)->d_next
== DC_AFTER_CLUSTER
||
219 item_convert_data(pos
)->d_next
== DC_INVALID_STATE
);
221 item_convert_data(pos
)->d_cur
= DC_AFTER_CLUSTER
;
222 item_convert_data(pos
)->d_next
= DC_INVALID_STATE
;
226 static inline int should_convert_node(flush_pos_t
*pos
, znode
* node
)
228 return znode_convertible(node
);
231 /* true if there is attached convert item info */
232 static inline int should_convert_next_node(flush_pos_t
*pos
)
234 return convert_data(pos
) && item_convert_data(pos
);
237 #define SQUALLOC_THRESHOLD 256
239 static inline int should_terminate_squalloc(flush_pos_t
*pos
)
241 return convert_data(pos
) &&
242 !item_convert_data(pos
) &&
243 item_convert_count(pos
) >= SQUALLOC_THRESHOLD
;
247 #define check_convert_info(pos) \
249 if (unlikely(should_convert_next_node(pos))) { \
250 warning("edward-1006", "unprocessed chained data"); \
251 printk("d_cur = %d, d_next = %d, flow.len = %llu\n", \
252 item_convert_data(pos)->d_cur, \
253 item_convert_data(pos)->d_next, \
254 item_convert_data(pos)->flow.length); \
258 #define check_convert_info(pos)
259 #endif /* REISER4_DEBUG */
261 void free_convert_data(flush_pos_t
*pos
);
262 /* used in extent.c */
263 int scan_set_current(flush_scan
* scan
, jnode
* node
, unsigned add_size
,
264 const coord_t
*parent
);
265 int reiser4_scan_finished(flush_scan
* scan
);
266 int reiser4_scanning_left(flush_scan
* scan
);
267 int reiser4_scan_goto(flush_scan
* scan
, jnode
* tonode
);
268 txn_atom
*atom_locked_by_fq(flush_queue_t
*fq
);
269 int reiser4_alloc_extent(flush_pos_t
*flush_pos
);
270 squeeze_result
squalloc_extent(znode
*left
, const coord_t
*, flush_pos_t
*,
271 reiser4_key
*stop_key
);
272 extern int reiser4_init_fqs(void);
273 extern void reiser4_done_fqs(void);
277 extern void reiser4_check_fq(const txn_atom
*atom
);
278 extern atomic_t flush_cnt
;
280 #define check_preceder(blk) \
281 assert("nikita-2588", blk < reiser4_block_count(reiser4_get_current_sb()));
282 extern void check_pos(flush_pos_t
*pos
);
284 #define check_preceder(b) noop
285 #define check_pos(pos) noop
288 /* __REISER4_FLUSH_H__ */
293 c-indentation-style: "K&R"