1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Information Systems Inc., 1983 *
  4    *                                                         *
  5    *********************************************************** */
  6 
  7 /* DESCRIPTION:
  8 
  9           This module splits the "old" control interval (identified by
 10      p_old_ci).  A new control interval is allocated which becomes the "old"
 11      control interval's new "left" sibling in the index.  This is referred to
 12      as the "new" control interval and its identifier is placed in p_new_ci.
 13 
 14           It is necessary to get the "old" control interval's original "left"
 15      sibling to update the doubly threaded list of siblings. The
 16      index_header's count of control intervals is also updated.
 17 */
 18 
 19 /* HISTORY:
 20 
 21 Written by Lindsey Spratt, 04/21/82.
 22 Modified:
 23 06/16/82 by Matthew Pierret: Removed the beginning_offset argument from
 24             calls to collection_manager_$put_element.
 25 08/09/82 by Matthew Pierret: Removed offset and length arguments from calls to
 26             collection_manager_$get_element.
 27 08/11/82 by Matthew Pierret:  Changed to use the aligned new_ci variable in the
 28             calling sequence to collection_manager_$allocate_control_interval.
 29 05/10/84 by Matthew Pierret:  Changed to align key_buffer on an even-word
 30             boundary.
 31 06/07/84 by Matthew Pierret:  Re-named cm_$get_element to cm_$get,
 32             cm_$put_element to cm_$modify, cm_$allocate_element to cm_$put.
 33 10/28/84 by Lindsey L. Spratt:  Changed to use version 2 of
 34             index_opening_info.  Changed to base old_common_ci_header and
 35             new_common_ci_header on automatic pointers instead of directly on
 36             parameters.
 37 03/07/85 by R. Michael Tague:  Changed opening info version to version 3.
 38 */
 39 ^L
 40 /* format: style2,ind3 */
 41 
 42 im_split:
 43    proc (p_index_opening_info_ptr, p_old_common_ci_header_ptr, p_old_ci, p_new_common_ci_header_ptr, p_new_ci, p_code);
 44 
 45 /* START OF DECLARATIONS */
 46 /* Parameter */
 47 
 48       dcl     p_index_opening_info_ptr
 49                                      ptr parameter;
 50       dcl     p_old_common_ci_header_ptr
 51                                      ptr;
 52       dcl     p_old_ci               fixed bin (24) unsigned unaligned;
 53       dcl     p_new_common_ci_header_ptr
 54                                      ptr;
 55       dcl     p_new_ci               fixed bin (24) unsigned unaligned;
 56       dcl     p_code                 fixed bin (35);
 57 
 58 /* Automatic */
 59 
 60       dcl     key_buffer             (DOUBLE_WORDS_PER_PAGE) fixed bin (71);
 61       dcl     key_buffer_length      fixed bin (35) init (BITS_PER_PAGE);
 62       dcl     key_length             fixed bin (35);
 63       dcl     new_ci                 fixed bin (24) unsigned;
 64       dcl     new_common_ci_header_ptr
 65                                      ptr init (null);
 66       dcl     old_common_ci_header_ptr
 67                                      ptr init (null);
 68       dcl     prev_ci                fixed bin (24) unsigned unaligned;
 69 
 70       dcl     1 local_leaf_ci_header like leaf_ci_header;
 71       dcl     1 local_branch_ci_header
 72                                      like branch_ci_header;
 73       dcl     splitting_leaf         bit (1) aligned;
 74       dcl     prev_common_header_ptr ptr;
 75 
 76 /* Based */
 77 
 78       dcl     1 old_common_header    like common_ci_header based (old_common_ci_header_ptr);
 79       dcl     1 new_common_header    like common_ci_header based (new_common_ci_header_ptr);
 80       dcl     1 prev_common_header   like common_ci_header based (prev_common_header_ptr);
 81 
 82 /* Builtin */
 83 
 84       dcl     null                   builtin;
 85       dcl     (addr, length, unspec) builtin;
 86 
 87 /* Controlled */
 88 /* Constant */
 89 
 90       dcl     BEGINNING_OF_ELEMENT   init (-1) fixed bin (35) internal static options (constant);
 91       dcl     BITS_PER_PAGE          init (36 * 1024) fixed bin (17) internal static options (constant);
 92       dcl     DOUBLE_WORDS_PER_PAGE  init (512) fixed bin (17) internal static options (constant);
 93       dcl     myname                 init ("im_split") char (32) varying internal static options (constant);
 94 
 95 
 96 /* Entry */
 97 
 98       dcl     sub_err_               entry () options (variable);
 99 
100       dcl     im_init_leaf_ci_header entry (ptr);
101       dcl     im_init_branch_ci_header
102                                      entry (ptr);
103 
104 /* External */
105 
106       dcl     error_table_$unimplemented_version
107                                      fixed bin (35) ext;
108 
109 /* END OF DECLARATIONS */
110 ^L
111       index_opening_info_ptr = p_index_opening_info_ptr;
112       call CHECK_VERSION (index_opening_info.version, INDEX_OPENING_INFO_VERSION_3, "index_opening_info");
113 
114       old_common_ci_header_ptr = p_old_common_ci_header_ptr;
115       new_common_ci_header_ptr = p_new_common_ci_header_ptr;
116 
117       splitting_leaf = old_common_header.is_leaf;
118 
119 /* Allocate a new control interval.  This is the new "left" sibling for p_old_ci. */
120 
121       call collection_manager_$allocate_control_interval (index_opening_info.file_opening_id,
122            index_opening_info.collection_id, new_ci, p_code);
123       if p_code ^= 0
124       then return;
125       else p_new_ci = new_ci;
126 
127 /* The header (leaf or branch) for the new ci must be initialized. */
128 
129       if splitting_leaf
130       then call im_init_leaf_ci_header (p_new_common_ci_header_ptr);
131       else call im_init_branch_ci_header (p_new_common_ci_header_ptr);
132       new_common_header.key_range = 0;
133 
134 /* Thread in with siblings ("old" and "prev"). */
135 
136       new_common_header.previous_id = old_common_header.previous_id;
137       new_common_header.next_id = p_old_ci;
138       old_common_header.previous_id = p_new_ci;
139       element_id.index = DEFAULT_INDEX_CONTROL_INTERVAL_HEADER_SLOT;
140       element_id.control_interval_id = p_new_ci;
141       if splitting_leaf
142       then call collection_manager_$put (index_opening_info.file_opening_id, index_opening_info.collection_id,
143                 p_new_common_ci_header_ptr, length (unspec (local_leaf_ci_header)), element_id_string, (0), p_code);
144       else call collection_manager_$put (index_opening_info.file_opening_id, index_opening_info.collection_id,
145                 p_new_common_ci_header_ptr, length (unspec (local_branch_ci_header)), element_id_string, (0), p_code);
146 
147 /* Adjust the parent of the split node so the old pointer to the split node
148 becomes a pointer to the new node (the split node's new left sibling).
149 */
150 
151       if addr (old_common_header.parent_id_string) -> element_id.control_interval_id ^= 0
152       then
153          do;
154             if addr (old_common_header.parent_id_string) -> element_id.index = 0
155             then
156                do;
157                   element_id_string = old_common_header.parent_id_string;
158                   element_id.index = DEFAULT_INDEX_CONTROL_INTERVAL_HEADER_SLOT;
159                   call collection_manager_$get (index_opening_info.file_opening_id, index_opening_info.collection_id,
160                        element_id_string, 0, addr (local_branch_ci_header), length (unspec (local_branch_ci_header)),
161                        null, "0"b, branch_ci_header_ptr, 0, p_code);
162                   if p_code ^= 0
163                   then return;
164 
165                   branch_ci_header.low_branch_id = p_new_ci;
166 
167 
168                   call collection_manager_$modify (index_opening_info.file_opening_id, index_opening_info.collection_id,
169                        branch_ci_header_ptr, length (unspec (local_branch_ci_header)), element_id_string, 0, p_code);
170                   if p_code ^= 0
171                   then return;
172                end;
173             else
174                do;
175                   element_id_string = old_common_header.parent_id_string;
176                   call collection_manager_$get (index_opening_info.file_opening_id, index_opening_info.collection_id,
177                        element_id_string, 0, addr (key_buffer), key_buffer_length, null, "0"b, branch_key_ptr, key_length,
178                        p_code);
179                   if p_code ^= 0
180                   then return;
181 
182                   bk_string_length = key_length - BRANCH_KEY_HEADER_LENGTH_IN_BITS;
183                   branch_key.branch_id = p_new_ci;
184 
185                   call collection_manager_$modify (index_opening_info.file_opening_id, index_opening_info.collection_id,
186                        branch_key_ptr, key_length, element_id_string, 0, p_code);
187                   if p_code ^= 0
188                   then return;
189 
190                end;
191          end;
192 
193 /* Pick up the "prev" (now the "new" node's "left" sibling) node's header.
194 This is adjusted to complete the threading in of the "new" node. */
195 
196       prev_ci = new_common_header.previous_id;
197       if prev_ci > 0
198       then
199          do;
200 
201             element_id.control_interval_id = prev_ci;
202             element_id.index = DEFAULT_INDEX_CONTROL_INTERVAL_HEADER_SLOT;
203 
204             if splitting_leaf
205             then call collection_manager_$get (index_opening_info.file_opening_id, index_opening_info.collection_id,
206                       element_id_string, (0), addr (local_leaf_ci_header), length (unspec (local_leaf_ci_header)), null,
207                       "0"b, prev_common_header_ptr, (0), p_code);
208             else call collection_manager_$get (index_opening_info.file_opening_id, index_opening_info.collection_id,
209                       element_id_string, (0), addr (local_branch_ci_header), length (unspec (local_branch_ci_header)),
210                       null, "0"b, prev_common_header_ptr, (0), p_code);
211             prev_common_header.next_id = p_new_ci;
212             if splitting_leaf
213             then call collection_manager_$modify (index_opening_info.file_opening_id, index_opening_info.collection_id,
214                       prev_common_header_ptr, length (unspec (local_leaf_ci_header)), element_id_string, (0), p_code);
215             else call collection_manager_$modify (index_opening_info.file_opening_id, index_opening_info.collection_id,
216                       prev_common_header_ptr, length (unspec (local_branch_ci_header)), element_id_string, (0), p_code);
217          end;
218 
219       return;
220 %page;
221 CHECK_VERSION:
222    proc (p_received_version, p_expected_version, p_structure_name);
223       dcl     p_received_version     char (8) aligned parameter;
224       dcl     p_expected_version     char (8) aligned parameter;
225       dcl     p_structure_name       char (*);
226 
227       if p_received_version ^= p_expected_version
228       then call sub_err_ (error_table_$unimplemented_version, myname, "s", null, 0,
229                 "^/Expected version ^d of the ^a structure.
230 Received version ^d instead.", p_expected_version, p_structure_name, p_received_version);
231 
232    end CHECK_VERSION;
233 %page;
234 %include dm_collmgr_entry_dcls;
235 %page;
236 %include dm_im_ci_header;
237 %page;
238 %include dm_im_key;
239 %page;
240 %include dm_im_opening_info;
241 %page;
242 %include dm_element_id;
243    end im_split;