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 flush-scan on a
11 single level of the tree. A flush-scan is used for counting the number of adjacent
12 nodes to flush, which is used to determine whether we should relocate, and it is also
13 used to find a starting point for flush. A flush-scan object can scan in both right
14 and left directions via the scan_left() and scan_right() interfaces. The
15 right- and left-variations are similar but perform different functions. When scanning
16 left we (optionally perform rapid scanning and then) longterm-lock the endpoint node.
17 When scanning right we are simply counting the number of adjacent, dirty nodes. */
20 /* The current number of nodes scanned on this level. */
23 /* There may be a maximum number of nodes for a scan on any single level. When
24 going leftward, max_count is determined by FLUSH_SCAN_MAXNODES (see reiser4.h) */
27 /* Direction: Set to one of the sideof enumeration: { LEFT_SIDE, RIGHT_SIDE }. */
30 /* Initially @stop is set to false then set true once some condition stops the
31 search (e.g., we found a clean node before reaching max_count or we found a
32 node belonging to another atom). */
35 /* The current scan position. If @node is non-NULL then its reference count has
36 been incremented to reflect this reference. */
39 /* A handle for zload/zrelse of current scan position node. */
42 /* During left-scan, if the final position (a.k.a. endpoint node) is formatted the
43 node is locked using this lock handle. The endpoint needs to be locked for
44 transfer to the flush_position object after scanning finishes. */
45 lock_handle node_lock
;
47 /* When the position is unformatted, its parent, coordinate, and parent
48 zload/zrelse handle. */
49 lock_handle parent_lock
;
51 load_count parent_load
;
53 /* The block allocator preceder hint. Sometimes flush_scan determines what the
54 preceder is and if so it sets it here, after which it is copied into the
55 flush_position. Otherwise, the preceder is computed later. */
56 reiser4_block_nr preceder_blk
;
59 struct convert_item_info
{
60 dc_item_stat d_cur
; /* disk cluster state of the current item */
61 dc_item_stat d_next
; /* disk cluster state of the next slum item */
67 int count
; /* for squalloc terminating */
68 item_plugin
*iplug
; /* current item plugin */
69 struct convert_item_info
*itm
; /* current item info */
70 struct cluster_handle clust
; /* transform cluster */
73 typedef enum flush_position_state
{
74 POS_INVALID
, /* Invalid or stopped pos, do not continue slum
76 POS_ON_LEAF
, /* pos points to already prepped, locked formatted node at
78 POS_ON_EPOINT
, /* pos keeps a lock on twig level, "coord" field is used
79 * to traverse unformatted nodes */
80 POS_TO_LEAF
, /* pos is being moved to leaf level */
81 POS_TO_TWIG
, /* pos is being moved to twig level */
82 POS_END_OF_TWIG
, /* special case of POS_ON_TWIG, when coord is after
83 * rightmost unit of the current twig */
84 POS_ON_INTERNAL
/* same as POS_ON_LEAF, but points to internal node */
87 /* An encapsulation of the current flush point and all the parameters that are passed
88 through the entire squeeze-and-allocate stage of the flush routine. A single
89 flush_position object is constructed after left- and right-scanning finishes. */
90 struct flush_position
{
91 flushpos_state_t state
;
93 coord_t coord
; /* coord to traverse unformatted nodes */
94 lock_handle lock
; /* current lock we hold */
95 load_count load
; /* load status for current locked formatted node */
97 jnode
*child
; /* for passing a reference to unformatted child
98 * across pos state changes */
100 reiser4_blocknr_hint preceder
; /* The flush 'hint' state. */
101 int leaf_relocate
; /* True if enough leaf-level nodes were
102 * found to suggest a relocate policy. */
103 int alloc_cnt
; /* The number of nodes allocated during squeeze and allococate. */
104 int prep_or_free_cnt
; /* The number of nodes prepared for write (allocate) or squeezed and freed. */
106 long *nr_written
; /* number of nodes submitted to disk */
107 int flags
; /* a copy of jnode_flush flags argument */
109 znode
*prev_twig
; /* previous parent pointer value, used to catch
110 * processing of new twig node */
111 struct convert_info
*sq
; /* convert info */
113 unsigned long pos_in_unit
; /* for extents only. Position
114 within an extent unit of first
116 long nr_to_write
; /* number of unformatted nodes to handle on flush */
119 static inline int item_convert_count(flush_pos_t
* pos
)
121 return pos
->sq
->count
;
123 static inline void inc_item_convert_count(flush_pos_t
* pos
)
127 static inline void set_item_convert_count(flush_pos_t
* pos
, int count
)
129 pos
->sq
->count
= count
;
131 static inline item_plugin
*item_convert_plug(flush_pos_t
* pos
)
133 return pos
->sq
->iplug
;
136 static inline struct convert_info
*convert_data(flush_pos_t
* pos
)
141 static inline struct convert_item_info
*item_convert_data(flush_pos_t
* pos
)
143 assert("edward-955", convert_data(pos
));
147 static inline struct tfm_cluster
* tfm_cluster_sq(flush_pos_t
* pos
)
149 return &pos
->sq
->clust
.tc
;
152 static inline struct tfm_stream
* tfm_stream_sq(flush_pos_t
* pos
,
155 assert("edward-854", pos
->sq
!= NULL
);
156 return get_tfm_stream(tfm_cluster_sq(pos
), id
);
159 static inline int chaining_data_present(flush_pos_t
* pos
)
161 return convert_data(pos
) && item_convert_data(pos
);
164 /* Returns true if next node contains next item of the disk cluster
165 so item convert data should be moved to the right slum neighbor.
167 static inline int should_chain_next_node(flush_pos_t
* pos
)
171 assert("edward-1007", chaining_data_present(pos
));
173 switch (item_convert_data(pos
)->d_next
) {
174 case DC_CHAINED_ITEM
:
177 case DC_AFTER_CLUSTER
:
180 impossible("edward-1009", "bad state of next slum item");
185 /* update item state in a disk cluster to assign conversion mode */
187 move_chaining_data(flush_pos_t
* pos
, int this_node
/* where is next item */ )
190 assert("edward-1010", chaining_data_present(pos
));
192 if (this_node
== 0) {
193 /* next item is on the right neighbor */
194 assert("edward-1011",
195 item_convert_data(pos
)->d_cur
== DC_FIRST_ITEM
||
196 item_convert_data(pos
)->d_cur
== DC_CHAINED_ITEM
);
197 assert("edward-1012",
198 item_convert_data(pos
)->d_next
== DC_CHAINED_ITEM
);
200 item_convert_data(pos
)->d_cur
= DC_CHAINED_ITEM
;
201 item_convert_data(pos
)->d_next
= DC_INVALID_STATE
;
203 /* next item is on the same node */
204 assert("edward-1013",
205 item_convert_data(pos
)->d_cur
== DC_FIRST_ITEM
||
206 item_convert_data(pos
)->d_cur
== DC_CHAINED_ITEM
);
207 assert("edward-1227",
208 item_convert_data(pos
)->d_next
== DC_AFTER_CLUSTER
||
209 item_convert_data(pos
)->d_next
== DC_INVALID_STATE
);
211 item_convert_data(pos
)->d_cur
= DC_AFTER_CLUSTER
;
212 item_convert_data(pos
)->d_next
= DC_INVALID_STATE
;
216 static inline int should_convert_node(flush_pos_t
* pos
, znode
* node
)
218 return znode_convertible(node
);
221 /* true if there is attached convert item info */
222 static inline int should_convert_next_node(flush_pos_t
* pos
)
224 return convert_data(pos
) && item_convert_data(pos
);
227 #define SQUALLOC_THRESHOLD 256
229 static inline int should_terminate_squalloc(flush_pos_t
* pos
)
231 return convert_data(pos
) &&
232 !item_convert_data(pos
) &&
233 item_convert_count(pos
) >= SQUALLOC_THRESHOLD
;
237 #define check_convert_info(pos) \
239 if (unlikely(should_convert_next_node(pos))){ \
240 warning("edward-1006", "unprocessed chained data"); \
241 printk("d_cur = %d, d_next = %d, flow.len = %llu\n", \
242 item_convert_data(pos)->d_cur, \
243 item_convert_data(pos)->d_next, \
244 item_convert_data(pos)->flow.length); \
245 printk("inode %llu, size = %llu, cluster %lu\n", \
246 (unsigned long long)get_inode_oid \
247 (item_convert_data(pos)->inode), \
248 i_size_read(item_convert_data(pos)->inode), \
249 convert_data(pos)->clust.index); \
253 #define check_convert_info(pos)
254 #endif /* REISER4_DEBUG */
256 void free_convert_data(flush_pos_t
* pos
);
257 /* used in extent.c */
258 int scan_set_current(flush_scan
* scan
, jnode
* node
, unsigned add_size
,
259 const coord_t
* parent
);
260 int reiser4_scan_finished(flush_scan
* scan
);
261 int reiser4_scanning_left(flush_scan
* scan
);
262 int reiser4_scan_goto(flush_scan
* scan
, jnode
* tonode
);
263 txn_atom
*atom_locked_by_fq(flush_queue_t
* fq
);
264 int reiser4_alloc_extent(flush_pos_t
*flush_pos
);
265 squeeze_result
squalloc_extent(znode
*left
, const coord_t
*, flush_pos_t
*,
266 reiser4_key
*stop_key
);
267 extern int reiser4_init_fqs(void);
268 extern void reiser4_done_fqs(void);
272 extern void reiser4_check_fq(const txn_atom
*atom
);
273 extern atomic_t flush_cnt
;
275 #define check_preceder(blk) \
276 assert("nikita-2588", blk < reiser4_block_count(reiser4_get_current_sb()));
277 extern void check_pos(flush_pos_t
* pos
);
279 #define check_preceder(b) noop
280 #define check_pos(pos) noop
283 /* __REISER4_FLUSH_H__ */
288 c-indentation-style: "K&R"