diff --git a/Event/EventBookkeeperTools/CMakeLists.txt b/Event/EventBookkeeperTools/CMakeLists.txt
index 4f364c640fdd205cceab125b3867c42398f43081..0f7d1f44b870a5f51829f6b0da422c1e8eed5ceb 100644
--- a/Event/EventBookkeeperTools/CMakeLists.txt
+++ b/Event/EventBookkeeperTools/CMakeLists.txt
@@ -6,44 +6,22 @@
 atlas_subdir( EventBookkeeperTools )
 
 if( XAOD_STANDALONE )
-   set( xaod_access_deps Control/xAODRootAccess )
    set( xaod_access_lib xAODRootAccess )
 # ... for AthAnalysisBase (Athena calls this POOLRootAccess)
 else()
-   set( xaod_access_deps PhysicsAnalysis/POOLRootAccess )
    set( xaod_access_lib POOLRootAccessLib )
 endif()
 
-# Declare the package's dependencies:
-atlas_depends_on_subdirs( PUBLIC
-                          Control/AthToolSupport/AsgTools
-                          Control/AthenaBaseComps
-                          Control/AthenaKernel
-                          Event/xAOD/xAODCutFlow
-                          GaudiKernel
-                          PRIVATE
-                          ${xaod_access_deps}
-                          Control/SGTools
-                          Control/StoreGate
-                          Event/EventBookkeeperMetaData
-                          Event/EventInfo
-                          Event/xAOD/xAODEventInfo )
-
-# External dependencies:
-find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
-
 # Component(s) in the package:
 atlas_add_component( EventBookkeeperTools
                      src/*.cxx
                      src/components/*.cxx
-                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${ROOT_LIBRARIES} AsgTools AthenaBaseComps AthenaKernel xAODCutFlow
-                                    GaudiKernel SGTools StoreGateLib SGtests EventBookkeeperMetaData EventInfo xAODEventInfo )
+                     LINK_LIBRARIES AsgTools AthenaBaseComps AthenaKernel GaudiKernel
+                                    SGTools StoreGateLib EventBookkeeperMetaData EventInfo xAODCutFlow xAODEventInfo )
 
 atlas_add_executable( dump-cbk
                       util/dump-cbk.cxx
-                      INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
-                      LINK_LIBRARIES ${ROOT_LIBRARIES} ${xaod_access_lib} AsgTools )  
+                      LINK_LIBRARIES ${xaod_access_lib} AsgTools )  
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py )
diff --git a/Event/EventBookkeeperTools/src/BookkeeperTool.cxx b/Event/EventBookkeeperTools/src/BookkeeperTool.cxx
index ac8ce9e8f80cb1bab716d3a820832908ee91bb8f..a198cbd6687aa92e4d68e6acf5847f6df76137fc 100644
--- a/Event/EventBookkeeperTools/src/BookkeeperTool.cxx
+++ b/Event/EventBookkeeperTools/src/BookkeeperTool.cxx
@@ -1,52 +1,28 @@
-///////////////////////// -*- C++ -*- /////////////////////////////
-
 /*
   Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // Implementation file for class BookkeeperTool
-// Authors: Jack Cranshaw <Jack.Cranshaw@cern.ch>
-///////////////////////////////////////////////////////////////////
+// Authors: Tadej Novak <tadej@cern.ch>
+//          Jack Cranshaw <Jack.Cranshaw@cern.ch>
 
 #include "BookkeeperTool.h"
-
-// STL include
-#include <algorithm>
-
-// #include "FillEBCFromFlat.h"
-
-#include "AthenaKernel/errorcheck.h"
-#include "AthenaBaseComps/AthCheckMacros.h"
-
+#include "CutBookkeeperUtils.h"
 #include "CutFlowSvc.h"
 
 
 BookkeeperTool::BookkeeperTool(const std::string& name)
-  : asg::AsgMetadataTool(name),
-    m_cutflowTaken(false)
+  : asg::AsgMetadataTool(name)
 {
-  declareProperty("OutputCollName", m_outputCollName="CutBookkeepers",  
-    "The default name of the xAOD::CutBookkeeperContainer for output files");
-  declareProperty("InputCollName", m_inputCollName = "CutBookkeepers",
-    "The default name of the xAOD::CutBookkeeperContainer for input files");
-
 #ifndef XAOD_STANDALONE
   declareInterface< ::IMetaDataTool >( this );
 #endif // XAOD_STANDALONE
 }
 
 
-
-BookkeeperTool::~BookkeeperTool()
+StatusCode BookkeeperTool::initialize()
 {
-}
-
-
-
-StatusCode
-BookkeeperTool::initialize()
-{
-  ATH_MSG_DEBUG( "Initializing " << name() << " - package version " << PACKAGE_VERSION );
+  ATH_MSG_DEBUG("Initializing " << name());
 
   ATH_MSG_DEBUG("InputCollName = " << m_inputCollName);
   ATH_MSG_DEBUG("OutputCollName = " << m_outputCollName);
@@ -59,178 +35,138 @@ BookkeeperTool::initialize()
 }
 
 
-//__________________________________________________________________________
-StatusCode BookkeeperTool::beginInputFile(const SG::SourceID&)
+StatusCode BookkeeperTool::beginInputFile(const SG::SourceID &source)
 {
-  //OPENING NEW INPUT FILE
-  //Things to do:
-  // 1) note that a file is currently opened
-  // 2) Load CutBookkeepers from input file
-  //    2a) if incomplete from input, directly propagate to output
-  //    2b) if complete from input, wait for EndInputFile to decide what to do in output
-
-  // reset cutflow taken marker
-  m_cutflowTaken = false;
+  // OPENING NEW INPUT FILE
+  // Things to do:
+  // 1) Load CutBookkeepers from input file
+  //    a) if incomplete from input, directly propagate to output
+  //    b) if complete from input, wait for EndInputFile to decide what to do in output
+
+  // Prepare local cache
+  ATH_CHECK(prepareContainers(m_completeContainers));
+  ATH_CHECK(prepareContainers(m_incompleteContainers));
+
+  // Check if a local container is there. IT SHOULD NOT BE
+  auto sit = m_inputContainers.find(source);
+  if (sit != m_inputContainers.end()) {
+    ATH_MSG_ERROR("Undefined behaviour: this file has already been processed");
+    return StatusCode::FAILURE;
+  }
 
   // Get the incomplete bookkeeper collection of the input metadata store
-  const xAOD::CutBookkeeperContainer* input_inc = 0;
+  const xAOD::CutBookkeeperContainer *inIncomplete{};
   // Construct input and output incomplete names
-  std::string inCollName = "Incomplete" + m_inputCollName;
-  std::string outCollName = "Incomplete" + m_outputCollName;
-  if (inputMetaStore()->contains<xAOD::CutBookkeeperContainer>(inCollName) ) {
-    StatusCode ssc = inputMetaStore()->retrieve( input_inc, inCollName );
-    if (ssc.isSuccess()) {
-      // First make sure there is an incomplete container in the output store
-      if( !(outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(outCollName)) ) {
-        xAOD::CutBookkeeperContainer* inc = new xAOD::CutBookkeeperContainer();
-        xAOD::CutBookkeeperAuxContainer* auxinc = new xAOD::CutBookkeeperAuxContainer();
-        inc->setStore(auxinc);
-        ATH_CHECK(outputMetaStore()->record(inc,outCollName));
-        ATH_CHECK(outputMetaStore()->record(auxinc,outCollName+"Aux."));
-      }
-      // retrieve the incomplete output container
-      xAOD::CutBookkeeperContainer* incompleteBook(NULL);
-      ATH_CHECK(outputMetaStore()->retrieve( incompleteBook, outCollName));
+  std::string incompleteCollName = "Incomplete" + m_inputCollName;
+  if (inputMetaStore()->contains<xAOD::CutBookkeeperContainer>(incompleteCollName)) {
+    if (inputMetaStore()->retrieve(inIncomplete, incompleteCollName).isSuccess()) {
       // update incomplete output with any incomplete input
-      ATH_CHECK(this->updateContainer(incompleteBook,input_inc));
+      ATH_CHECK(xAOD::CutBookkeeperUtils::updateContainer(m_incompleteContainers.at(0), inIncomplete));
       ATH_MSG_DEBUG("Successfully merged input incomplete bookkeepers with output");
     }
-  }
-  else {
-    ATH_MSG_INFO("No incomplete bookkeepers in this file " << inCollName);
+  } else {
+    ATH_MSG_INFO("No incomplete bookkeepers in this file with name " << incompleteCollName);
   }
 
   // Get the complete bookkeeper collection of the input metadata store
-  const xAOD::CutBookkeeperContainer* input_com = 0;
-  inCollName = m_inputCollName;
-  outCollName = m_outputCollName;
-  if (inputMetaStore()->contains<xAOD::CutBookkeeperContainer>(inCollName) ) {
-    if ( (inputMetaStore()->retrieve( input_com, inCollName )).isSuccess() ) {
-      // Check if a tmp is there. IT SHOULD NOT BE
-      //xAOD::CutBookkeeperContainer* incompleteBook(NULL);
-      if( !(outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(outCollName+"tmp")) ) {
-        // Now create the tmp container
-        xAOD::CutBookkeeperContainer* tmp = new xAOD::CutBookkeeperContainer();
-        xAOD::CutBookkeeperAuxContainer* auxtmp = new xAOD::CutBookkeeperAuxContainer();
-        tmp->setStore(auxtmp);
-        if (updateContainer(tmp,input_com).isSuccess()) {
-          ATH_CHECK(outputMetaStore()->record(tmp,outCollName+"tmp"));
-          ATH_CHECK(outputMetaStore()->record(auxtmp,outCollName+"tmpAux."));
-        }
-        else {
-          ATH_MSG_WARNING("Could not update tmp container from input complete conatiner");
-        }
-      }
+  const xAOD::CutBookkeeperContainer *inComplete{};
+  if (inputMetaStore()->contains<xAOD::CutBookkeeperContainer>(m_inputCollName)) {
+    if (inputMetaStore()->retrieve(inComplete, m_inputCollName).isSuccess()) {
+      // Create the temporary container
+      auto [it, status] = m_inputContainers.emplace(source, LocalContainers());
+      ATH_CHECK(prepareContainers(it->second));
+
+      ATH_CHECK(xAOD::CutBookkeeperUtils::updateContainer(it->second.at(0), inComplete));
+      ATH_MSG_DEBUG("Successfully copied complete bookkeepers to temp container");
+    } else {
+      ATH_MSG_INFO("No complete bookkeepers in this file with name " << m_inputCollName);
     }
-    else {
-      ATH_MSG_WARNING("tmp collection already exists");
-      return StatusCode::SUCCESS;
-    }
-    ATH_MSG_DEBUG("Successfully copied complete bookkeepers to temp container");
   }
 
-  //  Now make sure the output containers are in the output store
-  //
-  //  Make sure complete container exists in output
-  if( !(outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(m_outputCollName)) ) {
-      // Now create the complete container
-    xAOD::CutBookkeeperContainer* inc = new xAOD::CutBookkeeperContainer();
-    xAOD::CutBookkeeperAuxContainer* auxinc = new xAOD::CutBookkeeperAuxContainer();
-    inc->setStore(auxinc);
-    ATH_CHECK(outputMetaStore()->record(inc,m_outputCollName));
-    ATH_CHECK(outputMetaStore()->record(auxinc,m_outputCollName+"Aux."));
-  }
-  else {
-    ATH_MSG_WARNING("complete collection already exists");
-    //return StatusCode::SUCCESS;
-  }
-  //  Make sure incomplete container exists in output
-  std::string inc_name = "Incomplete"+m_outputCollName;
-  if( !(outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(inc_name)) ) {
-      // Now create the complete container
-    xAOD::CutBookkeeperContainer* coll = new xAOD::CutBookkeeperContainer();
-    xAOD::CutBookkeeperAuxContainer* auxcoll = new xAOD::CutBookkeeperAuxContainer();
-    coll->setStore(auxcoll);
-    ATH_CHECK(outputMetaStore()->record(coll,inc_name));
-    ATH_CHECK(outputMetaStore()->record(auxcoll,inc_name+"Aux."));
-  }
-  else {
-    ATH_MSG_WARNING("incomplete collection already exists");
-  }
-  
   return StatusCode::SUCCESS;
 }
 
 
-StatusCode BookkeeperTool::endInputFile(const SG::SourceID&)
+StatusCode BookkeeperTool::endInputFile(const SG::SourceID &source)
 {
+  ATH_CHECK(copyInputContainersToOutput(m_completeContainers, source));
 
-  if (copyContainerToOutput(m_outputCollName).isFailure()) return StatusCode::FAILURE;
-
-  if (!m_cutflowTaken) {
-    if (addCutFlow().isFailure()) {
-      ATH_MSG_ERROR("Could not add CutFlow information");
-    }
-    m_cutflowTaken = true;
-  }
-  else {
-    ATH_MSG_DEBUG("Cutflow information written into container before endInputFile");
-  }
-    
   return StatusCode::SUCCESS;
 }
 
 StatusCode BookkeeperTool::metaDataStop()
 {
-  //TERMINATING THE JOB (EndRun)
-  //Things to do:
+  // TERMINATING THE JOB (EndRun)
+  // Things to do:
   // 1) Create new incomplete CutBookkeepers if relevant
-  // 2) Print cut flow summary
-  // 3) Write root file if requested
-  //  Make sure incomplete container exists in output
-  std::string inc_name = "Incomplete"+m_outputCollName;
-  if (copyContainerToOutput(inc_name).isFailure()) return StatusCode::FAILURE;
+  // 2) Copy cutflow from the service
+  // 3) Copy containers to output
+
+  // All files that have not been fully processed are incomplete
+  ATH_CHECK(copyInputContainersToOutput(m_incompleteContainers));
 
+  // Copy cutflow from the service
+  ATH_CHECK(copyCutflowFromService());
 
-  if (!m_cutflowTaken) {
-    if (addCutFlow().isFailure()) {
-      ATH_MSG_ERROR("Could not add CutFlow information");
+  // Write out the containers
+  for (std::size_t i = 0; i < m_completeContainers.cont.size(); ++i) {
+    std::string name = m_outputCollName;
+    if (i != 0) {
+      name.append("_weight_");
+      name.append(std::to_string(i));
     }
-  }
-  else {
-    ATH_MSG_DEBUG("Cutflow information written into container before metaDataStop");
+
+    ATH_CHECK(outputMetaStore()->record(std::move(m_completeContainers.cont[i]), name));
+    ATH_CHECK(outputMetaStore()->record(std::move(m_completeContainers.aux[i]), name + "Aux."));
+    ATH_CHECK(outputMetaStore()->record(std::move(m_incompleteContainers.cont[i]), "Incomplete" + name));
+    ATH_CHECK(outputMetaStore()->record(std::move(m_incompleteContainers.aux[i]), "Incomplete" + name + "Aux."));
   }
 
-  // Reset after metadata stop
-  m_cutflowTaken = false;
-  
+  m_incompleteContainers.clear();
+  m_completeContainers.clear();
+
   return StatusCode::SUCCESS;
 }
 
 
-StatusCode
-BookkeeperTool::finalize()
+StatusCode BookkeeperTool::copyInputContainersToOutput(LocalContainers &target,
+                                                       const SG::SourceID &source)
 {
-  ATH_MSG_DEBUG( "Finalizing " << name() << " - package version " << PACKAGE_VERSION );
+  ATH_CHECK(prepareContainers(target));
+
+  if (!source.empty()) {
+    auto it = m_inputContainers.find(source);
+    if (it == m_inputContainers.end()) {
+      ATH_MSG_DEBUG("No input containers for this file");
+      return StatusCode::SUCCESS;
+    }
+
+    for (std::size_t i = 0; i < it->second.size(); ++i) {
+      ATH_CHECK(xAOD::CutBookkeeperUtils::updateContainer(target.at(i), it->second.at(i)));
+    }
+    m_inputContainers.erase(it);
+
+    return StatusCode::SUCCESS;
+  }
+
+  for (auto &[s, list] : m_inputContainers) {
+    for (std::size_t i = 0; i < list.size(); ++i) {
+      ATH_CHECK(xAOD::CutBookkeeperUtils::updateContainer(target.at(i), list.at(i)));
+    }
+  }
+  m_inputContainers.clear();
+
   return StatusCode::SUCCESS;
 }
 
-
-StatusCode BookkeeperTool::addCutFlow()
+StatusCode BookkeeperTool::copyCutflowFromService()
 {
-  // Add the information from the current processing to the complete output
-  // --> same paradigm as original CutFlowSvc
-  // Get the complete bookkeeper collection of the output meta-data store
-  xAOD::CutBookkeeperContainer* completeBook(NULL); 
-  if( !(outputMetaStore()->retrieve( completeBook, m_outputCollName) ).isSuccess() ) {
-    ATH_MSG_ERROR( "Could not get complete CutBookkeepers from output MetaDataStore" );
-    return StatusCode::FAILURE;
-  }
+  ATH_CHECK(prepareContainers(m_completeContainers));
 
   // Get the bookkeeper from the current processing
   const xAOD::CutBookkeeperContainer* cbkCont = m_cutFlowSvcPrivate->getCutBookkeepers();
   if (cbkCont != nullptr) {
-    ATH_CHECK(this->updateContainer(completeBook, cbkCont));
+    ATH_CHECK(xAOD::CutBookkeeperUtils::updateContainer(m_completeContainers.at(0), cbkCont));
   } else {
     ATH_MSG_ERROR("No cutflow container in the CutFlowSvc");
     return StatusCode::FAILURE;
@@ -240,170 +176,20 @@ StatusCode BookkeeperTool::addCutFlow()
 }
 
 
-namespace {
-
-
-xAOD::CutBookkeeper*
-resolveLink (const xAOD::CutBookkeeper* old,
-             xAOD::CutBookkeeperContainer& contToUpdate,
-             const xAOD::CutBookkeeperContainer& otherCont,
-             const std::vector<size_t>& otherIndices)
+StatusCode BookkeeperTool::prepareContainers(LocalContainers &target)
 {
-  {
-    xAOD::CutBookkeeperContainer::iterator matchIter = 
-      std::find( contToUpdate.begin(),
-                 contToUpdate.end(),
-                 old );
-    if (matchIter != contToUpdate.end())
-      return *matchIter;
+  if (!target.empty()) {
+    return StatusCode::SUCCESS;
   }
 
-  {
-    xAOD::CutBookkeeperContainer::const_iterator matchIter = 
-      std::find( otherCont.begin(),
-                 otherCont.end(),
-                 old );
-    if (matchIter != contToUpdate.end()) {
-      size_t pos = matchIter - otherCont.begin();
-      return contToUpdate[otherIndices[pos]];
-    }
-  }
-
-  // If we didn't find it, we need to add it
-  xAOD::CutBookkeeper* newEBK = new xAOD::CutBookkeeper();
-  if ( newEBK->usingPrivateStore() ) { newEBK->releasePrivateStore(); }
-  newEBK->makePrivateStore(old);
-  contToUpdate.push_back( newEBK );
-  return newEBK;
-}
-
-
-} // anonymous namespace
-
-StatusCode
-BookkeeperTool::updateContainer( xAOD::CutBookkeeperContainer* contToUpdate,
-                             const xAOD::CutBookkeeperContainer* otherCont ) 
-{
-  ATH_MSG_DEBUG("calling updateContainer(...)" );
-  ATH_MSG_VERBOSE("Have container to update with size=" << contToUpdate->size()
-                  << ", and other container with size=" << otherCont->size() );
-
-  size_t origSize = contToUpdate->size();
-
-  // Vector of indices in contToUpdate of elements in otherCont.
-  std::vector< std::size_t > otherIndices (otherCont->size());
-  // Loop through otherCont.
-  // If element already in contToUpdate, update event counts, otherwise create new element
-  for ( std::size_t i=0; i<otherCont->size(); ++i ) {
-    const xAOD::CutBookkeeper* otherEBK = otherCont->at(i);
-    ATH_MSG_VERBOSE("Looping through otherCont at index " << i);
-    ATH_MSG_VERBOSE("Have otherEBK with: name=" << otherEBK->name()
-                    << ", cycle=" << otherEBK->cycle()
-                    << ", nAcceptedEvents=" << otherEBK->nAcceptedEvents()
-                    << ", inputStream=" << otherEBK->inputStream() );
-
-
-    // Loop through the container to be updated (contToUpdate) and see if we find a match
-    bool foundEBKToUpdate(false);
-    for ( std::size_t j=0; j<contToUpdate->size(); ++j ) {
-      xAOD::CutBookkeeper* ebkToUpdate = contToUpdate->at(j);
-      // Check if they are identical, if so, update; else add otherEBK
-      if ( otherEBK->isEqualTo(ebkToUpdate) ) {
-        ebkToUpdate->setPayload( ebkToUpdate->payload() + otherEBK->payload() );
-        otherIndices[i] = j;
-        foundEBKToUpdate = true;
-        break;
-      }
-    } // End: Inner loop over contToUpdate
-    if (!foundEBKToUpdate) {
-      xAOD::CutBookkeeper* newEBK = new xAOD::CutBookkeeper();
-      if ( newEBK->usingPrivateStore() ) { newEBK->releasePrivateStore(); }
-      newEBK->makePrivateStore(otherEBK);
-      contToUpdate->push_back( newEBK );
-      std::size_t ebIdx = newEBK->index();
-      otherIndices[i] = ebIdx;
-    }
-  } // End: Outer loop over contToUpdate
-
-  // Now, we still need to fix the cross-referencing of the newly added CutBookkkeepers
-  for ( std::size_t i=origSize; i<contToUpdate->size(); ++i ) {
-    xAOD::CutBookkeeper* ebkToModify = contToUpdate->at(i);
-
-    // Parent check
-    if ( ebkToModify->hasParent() ) {
-      const xAOD::CutBookkeeper* oldParent = ebkToModify->parent();
-      const xAOD::CutBookkeeper* newParent = resolveLink (oldParent,
-                                                          *contToUpdate,
-                                                          *otherCont,
-                                                          otherIndices);
-      ebkToModify->setParent (newParent);
-    } // Done fixing parent
-
-    // Children check
-    std::vector< xAOD::CutBookkeeper* > newChildren;
-    for ( std::size_t oldIdx=0; oldIdx<ebkToModify->nChildren(); ++oldIdx ) {
-      const xAOD::CutBookkeeper* oldEBK = ebkToModify->child(oldIdx);
-      newChildren.push_back (resolveLink (oldEBK,
-                                          *contToUpdate,
-                                          *otherCont,
-                                          otherIndices));
-    } // Done fixing children
-    ebkToModify->setChildren (newChildren);
-
-    // Used others check
-    std::vector< xAOD::CutBookkeeper* > newOthers;
-    for ( std::size_t oldIdx=0; oldIdx<ebkToModify->nUsedOthers(); ++oldIdx ) {
-      const xAOD::CutBookkeeper* oldEBK = ebkToModify->usedOther(oldIdx);
-      newOthers.push_back (resolveLink (oldEBK,
-                                        *contToUpdate,
-                                        *otherCont,
-                                        otherIndices));
-    } // Done fixing used others
-    ebkToModify->setUsedOthers (newOthers);
-
-    // Siblings check
-    std::vector< xAOD::CutBookkeeper* > newSiblings;
-    for ( std::size_t oldIdx=0; oldIdx<ebkToModify->nSiblings(); ++oldIdx ) {
-      const xAOD::CutBookkeeper* oldEBK = ebkToModify->sibling(oldIdx);
-      newSiblings.push_back (resolveLink (oldEBK,
-                                          *contToUpdate,
-                                          *otherCont,
-                                          otherIndices));
-    } // Done fixing siblings
-    ebkToModify->setSiblings (newSiblings);
-  } // Done fixing all cross references
-  return StatusCode::SUCCESS;
-}
-
-
-StatusCode BookkeeperTool::copyContainerToOutput(const std::string& outname)
-{
-
-  // Get the complete bookkeeper collection of the output meta-data store
-  xAOD::CutBookkeeperContainer* contBook(nullptr); 
-  if( !(outputMetaStore()->retrieve( contBook, outname) ).isSuccess() ) {
-    ATH_MSG_ERROR( "Could not get " << outname << " CutBookkeepers from output MetaDataStore" );
-    return StatusCode::FAILURE;
+  std::size_t size{1}; // TODO: determine actual size
+  for (std::size_t i = 0; i < size; ++i) {
+    auto container = std::make_unique<xAOD::CutBookkeeperContainer>();
+    auto auxContainer = std::make_unique<xAOD::CutBookkeeperAuxContainer>();
+    container->setStore(auxContainer.get());
+    target.cont.push_back(std::move(container));
+    target.aux.push_back(std::move(auxContainer));
   }
 
-  // Get the tmp bookkeeper from the input
-  const xAOD::CutBookkeeperContainer* tmpBook(NULL);
-  if ( outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(m_outputCollName+"tmp") ) {
-    ATH_MSG_DEBUG("Copying data to the output container " << outname);
-    if( !(outputMetaStore()->retrieve( tmpBook, m_outputCollName+"tmp") ).isSuccess() ) {
-      ATH_MSG_WARNING( "Could not get tmp CutBookkeepers from output MetaDataStore" );
-    }
-    else {
-      // update the complete output with the complete input
-      ATH_CHECK(this->updateContainer(contBook,tmpBook));
-      // remove the tmp container
-      const SG::IConstAuxStore* tmpBookAux = tmpBook->getConstStore();
-      ATH_CHECK(outputMetaStore()->removeDataAndProxy(tmpBook));
-      ATH_CHECK(outputMetaStore()->removeDataAndProxy(tmpBookAux));
-    }
-  }
-    
   return StatusCode::SUCCESS;
 }
-
-
diff --git a/Event/EventBookkeeperTools/src/BookkeeperTool.h b/Event/EventBookkeeperTools/src/BookkeeperTool.h
index a60223fd2122c871fd3455141b1cb9f154c62062..3562be7cdd64286edeabe99d45c1ef26bdf20366 100644
--- a/Event/EventBookkeeperTools/src/BookkeeperTool.h
+++ b/Event/EventBookkeeperTools/src/BookkeeperTool.h
@@ -8,20 +8,22 @@
 /** @file BookkeeperTool.h
  *  @brief This class is an implementation of the AsgMetadataTool
  *  for the xAOD::CutBookkeeperContainer.
+ *  @author Tadej Novak <tadej@cern.ch>
  *  @author Jack Cranshaw <cranshaw@anl.gov>
- *  $Id: $
  **/
 
-//#include "GaudiKernel/AlgTool.h"
-#include "AthenaBaseComps/AthAlgTool.h"
-#include "AsgTools/AsgMetadataTool.h"
-#include "AthenaKernel/ICutFlowSvc.h"
+#include <memory>
+
+#include <AsgTools/AsgMetadataTool.h>
+#include <AthenaBaseComps/AthAlgTool.h>
+#include <AthenaKernel/ICutFlowSvc.h>
 #ifndef XAOD_STANDALONE
-#include "AthenaKernel/IMetaDataTool.h"
+#include <AthenaKernel/IMetaDataTool.h>
 #endif // XAOD_STANDALONE
-#include "GaudiKernel/ServiceHandle.h"
+#include <GaudiKernel/ServiceHandle.h>
 
 #include <xAODCutFlow/CutBookkeeperContainer.h>
+#include <xAODCutFlow/CutBookkeeperAuxContainer.h>
 
 class CutFlowSvc;
 
@@ -30,48 +32,63 @@ class BookkeeperTool : public asg::AsgMetadataTool
                      , public virtual ::IMetaDataTool
 #endif // XAOD_STANDALONE
 {
-   ASG_TOOL_CLASS0(BookkeeperTool)
+  ASG_TOOL_CLASS0(BookkeeperTool)
 public: // Constructor and Destructor
-   /// Standard Service Constructor
-   BookkeeperTool(const std::string& name = "BookkeeperTool");
-   /// Destructor
-   virtual ~BookkeeperTool();
+  /// Standard Service Constructor
+  BookkeeperTool(const std::string& name = "BookkeeperTool");
+  /// Destructor
+  virtual ~BookkeeperTool() = default;
 
+  /// Standard reimplemented functions
 public:
-   virtual StatusCode metaDataStop() override;
-   virtual StatusCode beginInputFile() override {return StatusCode::SUCCESS;}
-   virtual StatusCode endInputFile() override {return StatusCode::SUCCESS;}
-   virtual StatusCode beginInputFile(const SG::SourceID&) override;
-   virtual StatusCode endInputFile(const SG::SourceID&) override;
-   virtual StatusCode initialize() override;
-   virtual StatusCode finalize() override;
+  virtual StatusCode initialize() override;
+  virtual StatusCode metaDataStop() override;
+  virtual StatusCode beginInputFile() override {return StatusCode::SUCCESS;}
+  virtual StatusCode endInputFile() override {return StatusCode::SUCCESS;}
+  virtual StatusCode beginInputFile(const SG::SourceID &source) override;
+  virtual StatusCode endInputFile(const SG::SourceID &source) override;
 
 private:
-  
-  /// Helper class to update a container with information from another one
-  StatusCode updateContainer( xAOD::CutBookkeeperContainer* contToUpdate,
-                              const xAOD::CutBookkeeperContainer* otherCont );
+  /// Helper in-memory structure
+  struct LocalContainers {
+    std::vector<std::unique_ptr<xAOD::CutBookkeeperContainer>> cont;
+    std::vector<std::unique_ptr<xAOD::CutBookkeeperAuxContainer>> aux;
+
+    bool empty() { return cont.empty(); }
+    std::size_t size() { return cont.size(); }
+    xAOD::CutBookkeeperContainer *at(std::size_t n) { return cont.at(n).get(); }
+    void clear() { cont.clear(); aux.clear(); }
+  };
+
+  /// Copy input containers to the output
+  StatusCode copyInputContainersToOutput(LocalContainers &target,
+                                         const SG::SourceID &source = "");
 
-  StatusCode copyContainerToOutput(const std::string& outname);
+  /// Fill Cutflow information from the service
+  StatusCode copyCutflowFromService();
+
+  /// Prepare containers
+  StatusCode prepareContainers(LocalContainers &target);
 
-  /// Fill Cutflow information
-  StatusCode addCutFlow();
- 
   /// Pointer to the public CutFlowSvc interface
   ServiceHandle<ICutFlowSvc> m_cutFlowSvc{ this, "CutFlowSvc", "CutFlowSvc/CutFlowSvc", "Pointer to the CutFlowSvc"};
   /// Direct pointer to the CutFlowSvc for "private" methods access
   const CutFlowSvc *m_cutFlowSvcPrivate;
 
-  /// The name of the output CutBookkeeperContainer
-  std::string m_outputCollName;
-  
   /// The name of the input CutBookkeeperContainer
-  std::string  m_inputCollName;
+  Gaudi::Property<std::string> m_inputCollName{this, "InputCollName", "CutBookkeepers",
+    "The default name of the xAOD::CutBookkeeperContainer for input files"};
 
-  bool m_cutflowTaken;
-
-};
+  /// The name of the output CutBookkeeperContainer
+  Gaudi::Property<std::string> m_outputCollName{this, "OutputCollName", "CutBookkeepers",
+    "The default name of the xAOD::CutBookkeeperContainer for output files"};
 
-#endif
+  /// Input CutBookkeeperContainers
+  std::unordered_map<SG::SourceID, LocalContainers> m_inputContainers;
 
+  /// Local CutBookkeeperContainers
+  LocalContainers m_completeContainers;
+  LocalContainers m_incompleteContainers;
+};
 
+#endif // BOOKKEEPERTOOL_H
diff --git a/Event/EventBookkeeperTools/src/CutBookkeeperUtils.cxx b/Event/EventBookkeeperTools/src/CutBookkeeperUtils.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b1ef7692ef35e95bd56da8f534139bd2b93521ad
--- /dev/null
+++ b/Event/EventBookkeeperTools/src/CutBookkeeperUtils.cxx
@@ -0,0 +1,124 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CutBookkeeperUtils.h"
+
+namespace xAOD::CutBookkeeperUtils
+{
+
+xAOD::CutBookkeeper *resolveLink(const xAOD::CutBookkeeper *old,
+                                 xAOD::CutBookkeeperContainer &contToUpdate,
+                                 const xAOD::CutBookkeeperContainer &otherCont,
+                                 const std::vector<size_t> &otherIndexMap)
+{
+  {
+    xAOD::CutBookkeeperContainer::iterator matchIter = 
+      std::find(contToUpdate.begin(), contToUpdate.end(), old);
+    if (matchIter != contToUpdate.end()) {
+      return *matchIter;
+    }
+  }
+
+  {
+    xAOD::CutBookkeeperContainer::const_iterator matchIter = 
+      std::find(otherCont.begin(), otherCont.end(), old);
+    if (matchIter != contToUpdate.end()) {
+      std::size_t pos = matchIter - otherCont.begin();
+      return contToUpdate[otherIndexMap[pos]];
+    }
+  }
+
+  // If we didn't find it, we need to add it
+  xAOD::CutBookkeeper *newEBK = new xAOD::CutBookkeeper(); // will be owned by the container
+  if (newEBK->usingPrivateStore()) { newEBK->releasePrivateStore(); }
+  newEBK->makePrivateStore(old);
+  contToUpdate.push_back(newEBK);
+  return newEBK;
+}
+
+StatusCode updateContainer(xAOD::CutBookkeeperContainer *contToUpdate,
+                           const xAOD::CutBookkeeperContainer *otherCont) 
+{
+  size_t origSize = contToUpdate->size();
+
+  // Vector of indices in contToUpdate of elements in otherCont.
+  std::vector<std::size_t> otherIndexMap(otherCont->size());
+  // Loop through otherCont.
+  // If element already in contToUpdate, update event counts, otherwise create new element
+  for (std::size_t i = 0; i < otherCont->size(); ++i) {
+    const xAOD::CutBookkeeper *otherEBK = otherCont->at(i);
+
+    // Loop through the container to be updated (contToUpdate) and see if we find a match
+    bool foundEBKToUpdate{false};
+    for (std::size_t j = 0; j < contToUpdate->size(); ++j) {
+      xAOD::CutBookkeeper *ebkToUpdate = contToUpdate->at(j);
+      // Check if they are identical, if so, update; else add otherEBK
+      if (otherEBK->isEqualTo(ebkToUpdate)) {
+        ebkToUpdate->setPayload(ebkToUpdate->payload() + otherEBK->payload());
+        otherIndexMap[i] = j;
+        foundEBKToUpdate = true;
+        break;
+      }
+    } // End: Inner loop over contToUpdate
+    if (!foundEBKToUpdate) {
+      xAOD::CutBookkeeper *newEBK = new xAOD::CutBookkeeper(); // will be owned by the container
+      if (newEBK->usingPrivateStore()) { newEBK->releasePrivateStore(); }
+      newEBK->makePrivateStore(otherEBK);
+      contToUpdate->push_back(newEBK);
+      std::size_t ebIdx = newEBK->index();
+      otherIndexMap[i] = ebIdx;
+    }
+  } // End: Outer loop over contToUpdate
+
+  // Now, we still need to fix the cross-referencing of the newly added CutBookkkeepers
+  for (std::size_t i = origSize; i < contToUpdate->size(); ++i) {
+    xAOD::CutBookkeeper *ebkToModify = contToUpdate->at(i);
+
+    // Parent check
+    if (ebkToModify->hasParent()) {
+      const xAOD::CutBookkeeper *oldParent = ebkToModify->parent();
+      const xAOD::CutBookkeeper *newParent = resolveLink (oldParent,
+                                                          *contToUpdate,
+                                                          *otherCont,
+                                                          otherIndexMap);
+      ebkToModify->setParent (newParent);
+    } // Done fixing parent
+
+    // Children check
+    std::vector<xAOD::CutBookkeeper *> newChildren;
+    for ( std::size_t oldIdx = 0; oldIdx < ebkToModify->nChildren(); ++oldIdx) {
+      const xAOD::CutBookkeeper *oldEBK = ebkToModify->child(oldIdx);
+      newChildren.push_back(resolveLink(oldEBK,
+                                        *contToUpdate,
+                                        *otherCont,
+                                        otherIndexMap));
+    } // Done fixing children
+    ebkToModify->setChildren(newChildren);
+
+    // Used others check
+    std::vector<xAOD::CutBookkeeper *> newOthers;
+    for (std::size_t oldIdx = 0; oldIdx < ebkToModify->nUsedOthers(); ++oldIdx) {
+      const xAOD::CutBookkeeper *oldEBK = ebkToModify->usedOther(oldIdx);
+      newOthers.push_back(resolveLink(oldEBK,
+                                      *contToUpdate,
+                                      *otherCont,
+                                      otherIndexMap));
+    } // Done fixing used others
+    ebkToModify->setUsedOthers(newOthers);
+
+    // Siblings check
+    std::vector<xAOD::CutBookkeeper*> newSiblings;
+    for (std::size_t oldIdx = 0; oldIdx < ebkToModify->nSiblings(); ++oldIdx) {
+      const xAOD::CutBookkeeper *oldEBK = ebkToModify->sibling(oldIdx);
+      newSiblings.push_back(resolveLink(oldEBK,
+                                        *contToUpdate,
+                                        *otherCont,
+                                        otherIndexMap));
+    } // Done fixing siblings
+    ebkToModify->setSiblings(newSiblings);
+  } // Done fixing all cross references
+  return StatusCode::SUCCESS;
+}
+
+} // xAOD::CutBookkeeperUtils
diff --git a/Event/EventBookkeeperTools/src/CutBookkeeperUtils.h b/Event/EventBookkeeperTools/src/CutBookkeeperUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..beaaef324bf0fd0d7a8ae9b58bce350bc093a2ac
--- /dev/null
+++ b/Event/EventBookkeeperTools/src/CutBookkeeperUtils.h
@@ -0,0 +1,19 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef CUTBOOKKEEPERUTILS_H
+#define CUTBOOKKEEPERUTILS_H
+
+#include <xAODCutFlow/CutBookkeeperContainer.h>
+
+namespace xAOD::CutBookkeeperUtils
+{
+
+  /// @brief Helper function to update a container with information from another one
+  StatusCode updateContainer(xAOD::CutBookkeeperContainer *contToUpdate,
+                             const xAOD::CutBookkeeperContainer *otherCont);
+
+} // xAOD::CutBookkeepersUtils
+
+#endif // CUTBOOKKEEPERUTILS_H