nodes: 0, module; 1, function_definition; 2, function_name:down; 3, parameters; 4, block; 5, identifier:job; 6, identifier:input_file_id; 7, identifier:n; 8, identifier:down_checkpoints; 9, expression_statement; 10, comment:# Read the file; 11, expression_statement; 12, expression_statement; 13, if_statement; 14, comment:"""Input is a file and a range into that file to sort and an output location in which
      to write the sorted file.
      If the range is larger than a threshold N the range is divided recursively and
      a follow on job is then created which merges back the results. Otherwise,
      the file is sorted and placed in the output.
      """; 15, assignment; 16, assignment; 17, comparison_operator:length > n; 18, comment:# We will subdivide the file; 19, block; 20, else_clause; 21, identifier:input_file; 22, call; 23, identifier:length; 24, call; 25, identifier:length; 26, identifier:n; 27, expression_statement; 28, comment:# Split the file into two copies; 29, expression_statement; 30, expression_statement; 31, with_statement; 32, expression_statement; 33, with_statement; 34, comment:# Call the down function recursively; 35, return_statement; 36, comment:# We can sort this bit of the file; 37, block; 38, attribute; 39, argument_list; 40, attribute; 41, argument_list; 42, call; 43, assignment; 44, assignment; 45, with_clause; 46, block; 47, assignment; 48, with_clause; 49, block; 50, call; 51, expression_statement; 52, comment:# Sort the copy and write back to the fileStore; 53, expression_statement; 54, expression_statement; 55, return_statement; 56, attribute; 57, identifier:readGlobalFile; 58, identifier:input_file_id; 59, keyword_argument; 60, attribute; 61, identifier:getsize; 62, identifier:input_file; 63, attribute; 64, argument_list; 65, identifier:mid_point; 66, call; 67, identifier:t1; 68, call; 69, with_item; 70, expression_statement; 71, identifier:t2; 72, call; 73, with_item; 74, expression_statement; 75, attribute; 76, argument_list; 77, call; 78, assignment; 79, call; 80, call; 81, identifier:job; 82, identifier:fileStore; 83, identifier:cache; 84, False; 85, identifier:os; 86, identifier:path; 87, attribute; 88, identifier:logToMaster; 89, binary_operator:"Splitting file: %s of size: %s"
                                    % (input_file_id, length); 90, keyword_argument; 91, identifier:get_midpoint; 92, argument_list; 93, attribute; 94, argument_list; 95, as_pattern; 96, call; 97, attribute; 98, argument_list; 99, as_pattern; 100, call; 101, call; 102, identifier:rv; 103, attribute; 104, argument_list; 105, identifier:output_file; 106, call; 107, identifier:sort; 108, argument_list; 109, attribute; 110, argument_list; 111, identifier:job; 112, identifier:fileStore; 113, string:"Splitting file: %s of size: %s"; 114, tuple; 115, identifier:level; 116, attribute; 117, identifier:input_file; 118, integer:0; 119, identifier:length; 120, attribute; 121, identifier:getLocalTempFile; 122, call; 123, as_pattern_target; 124, identifier:copy_subrange_of_file; 125, argument_list; 126, attribute; 127, identifier:getLocalTempFile; 128, call; 129, as_pattern_target; 130, identifier:copy_subrange_of_file; 131, argument_list; 132, attribute; 133, argument_list; 134, attribute; 135, identifier:logToMaster; 136, binary_operator:"Sorting file: %s of size: %s"
                                    % (input_file_id, length); 137, keyword_argument; 138, attribute; 139, argument_list; 140, identifier:input_file; 141, identifier:output_file; 142, attribute; 143, identifier:writeGlobalFile; 144, identifier:output_file; 145, identifier:input_file_id; 146, identifier:length; 147, identifier:logging; 148, identifier:CRITICAL; 149, identifier:job; 150, identifier:fileStore; 151, identifier:open; 152, argument_list; 153, identifier:fH; 154, identifier:input_file; 155, integer:0; 156, binary_operator:mid_point + 1; 157, identifier:fH; 158, identifier:job; 159, identifier:fileStore; 160, identifier:open; 161, argument_list; 162, identifier:fH; 163, identifier:input_file; 164, binary_operator:mid_point + 1; 165, identifier:length; 166, identifier:fH; 167, identifier:job; 168, identifier:addFollowOnJobFn; 169, identifier:up; 170, call; 171, call; 172, identifier:job; 173, identifier:fileStore; 174, string:"Sorting file: %s of size: %s"; 175, tuple; 176, identifier:level; 177, attribute; 178, attribute; 179, identifier:getLocalTempFile; 180, identifier:job; 181, identifier:fileStore; 182, identifier:t1; 183, string; 184, identifier:mid_point; 185, integer:1; 186, identifier:t2; 187, string; 188, identifier:mid_point; 189, integer:1; 190, attribute; 191, argument_list; 192, attribute; 193, argument_list; 194, identifier:input_file_id; 195, identifier:length; 196, identifier:logging; 197, identifier:CRITICAL; 198, identifier:job; 199, identifier:fileStore; 200, string_content:w; 201, string_content:w; 202, call; 203, identifier:rv; 204, call; 205, identifier:rv; 206, attribute; 207, argument_list; 208, attribute; 209, argument_list; 210, identifier:job; 211, identifier:addChildJobFn; 212, identifier:down; 213, call; 214, identifier:n; 215, keyword_argument; 216, keyword_argument; 217, identifier:job; 218, identifier:addChildJobFn; 219, identifier:down; 220, call; 221, identifier:n; 222, keyword_argument; 223, keyword_argument; 224, attribute; 225, argument_list; 226, identifier:down_checkpoints; 227, identifier:down_checkpoints; 228, identifier:memory; 229, string; 230, attribute; 231, argument_list; 232, identifier:down_checkpoints; 233, identifier:down_checkpoints; 234, identifier:memory; 235, string; 236, attribute; 237, identifier:writeGlobalFile; 238, identifier:t1; 239, string_content:600M; 240, attribute; 241, identifier:writeGlobalFile; 242, identifier:t2; 243, string_content:600M; 244, identifier:job; 245, identifier:fileStore; 246, identifier:job; 247, identifier:fileStore
code: def down(job, input_file_id, n, down_checkpoints):
      """Input is a file and a range into that file to sort and an output location in which
      to write the sorted file.
      If the range is larger than a threshold N the range is divided recursively and
      a follow on job is then created which merges back the results. Otherwise,
      the file is sorted and placed in the output.
      """
      # Read the file
      input_file = job.fileStore.readGlobalFile(input_file_id, cache=False)
      length = os.path.getsize(input_file)
      if length > n:
          # We will subdivide the file
          job.fileStore.logToMaster("Splitting file: %s of size: %s"
                                    % (input_file_id, length), level=logging.CRITICAL)
          # Split the file into two copies
          mid_point = get_midpoint(input_file, 0, length)
          t1 = job.fileStore.getLocalTempFile()
          with open(t1, 'w') as fH:
              copy_subrange_of_file(input_file, 0, mid_point + 1, fH)
          t2 = job.fileStore.getLocalTempFile()
          with open(t2, 'w') as fH:
              copy_subrange_of_file(input_file, mid_point + 1, length, fH)
  
          # Call the down function recursively
          return job.addFollowOnJobFn(up, job.addChildJobFn(down, job.fileStore.writeGlobalFile(t1), n,
                                      down_checkpoints=down_checkpoints, memory='600M').rv(),
                                      job.addChildJobFn(down, job.fileStore.writeGlobalFile(t2), n,
                                                        down_checkpoints=down_checkpoints,
                                                        memory='600M').rv()).rv()
      else:
          # We can sort this bit of the file
          job.fileStore.logToMaster("Sorting file: %s of size: %s"
                                    % (input_file_id, length), level=logging.CRITICAL)
          # Sort the copy and write back to the fileStore
          output_file = job.fileStore.getLocalTempFile()
          sort(input_file, output_file)
          return job.fileStore.writeGlobalFile(output_file)