anchor.diff:  %%====================================================================
   
   %%--------------------------------------------------------------------
  +%% Function: chunkify_new_piece(Id, PieceSet) -> ok | none_eligible
  +%% Description: Find a piece in the PieceSet which has not been chunked
  +%%  yet and chunk it. Returns either ok if a piece was chunked or none_eligible
  +%%  if we can't find anything to chunk up in the PieceSet.
  +%%
  +%% TODO: Optimization possible: return the piece number we chunked up,
  +%%   so pick_chunks/2 can shortcut the selection.
  +%%--------------------------------------------------------------------
  +chunkify_new_piece(Id, PieceSet) when is_integer(Id) ->
  +    mnesia:transaction(
  +      fun () ->
  +	      Q1 = qlc:q([S || R <- mnesia:table(piece),
  +			       S <- sets:to_list(PieceSet),
  +			       R#piece.id =:= Id,
  +			       R#piece.piece_number =:= S,
  +			       R#piece.state =:= not_fetched]),
  +	      Eligible = qlc:e(Q1, {max_list_size, 1}),
  +	      case Eligible of
  +		  [] ->
  +		      none_eligible;
  +		  [P] ->
  +		      chunkify_piece(Id, P),
  +		      ok
  +	      end
  +      end).
  +
  +
  +%%--------------------------------------------------------------------
  +%% Function: select_chunks_by_piecenum(Id, PieceNum, Num, Pid) ->
  +%%     {ok, [{Offset, Len}]} | {partial, [{Offset, Len}], Remain}
  +%% Description: Select up to Num chunks from PieceNum. Will return either
  +%%  {ok, Chunks} if it got all chunks it wanted, or {partial, Chunks, Remain}
  +%%  if it got some chunks and there is still Remain chunks left to pick.
  +%%--------------------------------------------------------------------
  +select_chunks_by_piecenum(Id, PieceNum, Num, Pid) ->
  +    %% Pick up to Num chunks
  +    [R] = mnesia:read(chunk, {Id, PieceNum, not_fetched}, write),
  +    {Return, Rest} = lists:split(Num, R#chunk.chunks),
  +    [_|_] = Return, % Assert the state of Return
  +
  +    %% Explain to the tables we took some chunks
  +    [Q] = mnesia:read(chunk, {Pid, PieceNum, {assigned, Pid}}, write),
  +    mnesia:write(Q#chunk { chunks = Q#chunk.chunks ++ Return}),
  +
  +    %% Based on how much is left, not_fetched, we should update correctly
  +    case Rest of
  +	[] ->
  +	    %% Nothing left, we may not have got everything
  +	    mnesia:delete_object(R),
  +	    Remaining = Num - length(Return),
  +	    {ok, Return, Remaining};
  +	[_|_] ->
  +	    %% More left, we got everything we wanted to get
  +	    mnesia:write(R#chunk {chunks = Rest}),
  +	    {ok, Return, 0}
  +    end.
  +
  +%%--------------------------------------------------------------------
  +%% Function: add_piece_chunks(R, PieceSize) -> {atomic, ok} | {aborted, Reason}
  +%% Description: Add the chunks for a given piece to the #chunk table.
  +%%--------------------------------------------------------------------
  +add_piece_chunks(R, PieceSize) ->
  +    {ok, Chunks, NumChunks} = chunkify(PieceSize),
  +    mnesia:transaction(
  +      fun () ->
  +	      ok = mnesia:write(R#piece{ state = chunked,
  +					 left = NumChunks}),
  +	      ok = mnesia:write(#chunk { idt = {R#piece.id, R#piece.piece_number, not_fetched},
  +					 chunks = Chunks})
  +      end).
  +
  +%%--------------------------------------------------------------------
   %% Function: invariant_check(PList) -> ok | error
   %% Description: Check that a list of chunks for a full piece obeys some
   %%   invariants. This piece of code is there mostly as a debugging tool,
  
positive.code:     mnesia:transaction(
        fun () ->
  	      [Rows] = mnesia:select(chunk, [{MatchHead, [], ['$_']}]),
  	      lists:foreach(fun(C) ->
  				    {Id, PieceNum, _} = C#chunk.idt,
  				    Chunks = C#chunk.chunks,
  				    NotFetchIdt = {Id, PieceNum, not_fetched},
  				    case mnesia:read(chunk, NotFetchIdt, write) of
  					[] ->
  					    mnesia:write(#chunk{ idt = NotFetchIdt,
  								 chunks = Chunks});
  					[R] ->
  					    mnesia:write(R#chunk { chunks =
  								     R#chunk.chunks ++ Chunks})
  				    end
  			    end,
  			    Rows)
        end).
  
  %%--------------------------------------------------------------------
  
negative.code:     chunkify(ChunkSize, Offset+Left, 0,
  	     [{Offset, Left} | Acc]).
  
  
  %%--------------------------------------------------------------------
  %% Function: chunkify_piece(Id, PieceNum) -> {atomic, ok} | {aborted, Reason}
  %% Description: Given a PieceNumber, cut it up into chunks and add those
  %%   to the chunk table.
  %%--------------------------------------------------------------------
  chunkify_piece(Id, P) when is_record(P, piece) ->
      mnesia:transaction(
        fun () ->
  	      add_piece_chunks(P, etorrent_fs:size_of_ops(P#piece.files)),
  	      %% XXX: This can be optimized. Track this in the #torrent table
  	      Q1 = qlc:q([T || T <- mnesia:table(piece),
  			       T#piece.id =:= Id,
  			       T#piece.state =:= not_fetched]),
  	      case length(qlc:e(Q1)) of
  		  0 ->
  		      {atomic, _} =
  			  etorrent_torrent:statechange(Id, endgame),
  		      ok;
  		  N when is_integer(N) ->
  		      ok
  	      end
        end).
  
  