From 67c6b8ba06b4cff11b1661092944586f2fa6c682 Mon Sep 17 00:00:00 2001
From: Matthew McGill <mhollismcgill@gmail.com>
Date: Thu, 4 Oct 2018 15:35:05 +0000
Subject: [PATCH] Interface changes

Former-commit-id: d11ee2a0bc2d48d2305abfe9522540efd79a930b
---
 libIRDB/include/libIRDB-util.hpp      |   2 +-
 libIRDB/include/util/IRDB_Objects.hpp |  69 +++++++
 libIRDB/include/util/IR_Files.hpp     |  46 -----
 libIRDB/src/util/IRDB_Objects.cpp     | 275 ++++++++++++++++++++++++++
 libIRDB/src/util/IR_Files.cpp         |  97 ---------
 libIRDB/src/util/SConscript           |   2 +-
 6 files changed, 346 insertions(+), 145 deletions(-)
 create mode 100644 libIRDB/include/util/IRDB_Objects.hpp
 delete mode 100644 libIRDB/include/util/IR_Files.hpp
 create mode 100644 libIRDB/src/util/IRDB_Objects.cpp
 delete mode 100644 libIRDB/src/util/IR_Files.cpp

diff --git a/libIRDB/include/libIRDB-util.hpp b/libIRDB/include/libIRDB-util.hpp
index 3abc9a34a..dad1f7ead 100644
--- a/libIRDB/include/libIRDB-util.hpp
+++ b/libIRDB/include/libIRDB-util.hpp
@@ -36,7 +36,7 @@ namespace libIRDB
 #include <util/insn_preds.hpp>
 #include <util/IBT_Provenance.hpp>
 #include <util/params.hpp>
-#include <util/IR_Files.hpp>
+#include <util/IRDB_Objects.hpp>
 
 };
 
diff --git a/libIRDB/include/util/IRDB_Objects.hpp b/libIRDB/include/util/IRDB_Objects.hpp
new file mode 100644
index 000000000..41f062525
--- /dev/null
+++ b/libIRDB/include/util/IRDB_Objects.hpp
@@ -0,0 +1,69 @@
+#ifndef IRDB_Objects_h
+#define IRDB_Objects_h
+
+#include <map>
+#include <utility>
+#include <memory>
+
+
+// TODO: Should really use unordered maps but was getting build errors
+
+
+// *** A toolchain step should NOT delete pointers to any variant, file IR, or file object stored
+//     in a IRFiles_t object. I have made pointers shared where possible to communicate this. ***
+class IRDBObjects_t
+{
+	public:
+		IRDBObjects_t() 
+                {
+                    // set up interface to the sql server
+                    BaseObj_t::SetInterface(&pqxx_interface);
+                };
+		~IRDBObjects_t();
+
+		// Add/delete file IRs for a variant. Takes in the base ID of the
+                // file (File_t) that the FileIR_t is paired with. 
+                // Cannot delete a file IR if it is also owned outside this object.
+		// When deleting file IRs, have the option to write back to the DB.
+                // If the write fails, the IR is still deleted.
+		int AddFileIR(db_id_t variant_id, db_id_t file_id);
+		int DeleteFileIR(db_id_t file_id, bool write_to_DB);
+                // Add or delete a variant
+                // When deleting a variant, have the option to write back to the DB.
+                // Cannot delete a variant if it or its files are also owned outside this object.
+                // If the write fails, the variant is still deleted.
+                // Writing a variant does NOT write its files' IRs, but DOES delete them!
+                int AddVariant(db_id_t variant_id); 
+                int DeleteVariant(db_id_t variant_id, bool write_to_DB);
+                
+                // get a variant
+                // returns shared_ptr(NULL) if no such variant
+		std::shared_ptr<VariantID_t> GetVariant(db_id_t variant_id);
+		// get a file IR
+                // returns shared_ptr(NULL) if no such file IR
+		std::shared_ptr<FileIR_t> GetFileIR(db_id_t file_id);
+                // get a file
+                // returns shared_ptr(NULL) if no such file
+                std::shared_ptr<File_t> GetFile(db_id_t file_id);
+                // Get DB interface
+                pqxxDB_t* GetDBInterface();
+
+		// Write back all variants and file IRs stored in this IRFiles_t object.
+                // Also removes all variants and file IRs even if some writes fail.
+                // Returns 1 if any writes fail.
+                // Does NOT commit changes.
+		bool WriteBackAll(void);
+		
+	private:
+                pqxxDB_t pqxx_interface;
+		// maps for speed of finding needed files, file IRs and/or variants
+		// that have already been read from the DB
+                
+                // maps variant id to variant
+		std::map<db_id_t, std::shared_ptr<VariantID_t>> variant_map;
+                // maps file id to (file, file ir)
+		std::map<db_id_t, std::pair<std::shared_ptr<File_t>, std::shared_ptr<FileIR_t>>> file_IR_map;
+};
+
+#endif
+ 
diff --git a/libIRDB/include/util/IR_Files.hpp b/libIRDB/include/util/IR_Files.hpp
deleted file mode 100644
index 346826f09..000000000
--- a/libIRDB/include/util/IR_Files.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef IR_Files_h
-#define IR_Files_h
-
-// TODO: This should really use unordered maps and sets,
-//       but I was having trouble building with those.
-#include <map>
-#include <utility>
-#include <memory>
-#include <set>
-
-// If our toolchain use paradigm changes, this class can be extended
-// to support adding, removing, writing back, and getting individual file IRs
-// in a variant (may require adding more maps).
-
-// *** A toolchain step should NOT delete pointers to any variant, file IR, or file object stored
-//     in a IRFiles_t object. I have made pointers shared where possible to communicate this. ***
-class IRFiles_t
-{
-	public:
-		IRFiles_t() {};
-		~IRFiles_t();
-
-		// Add/remove file IRs.
-		// Adding file IRs also adds the variant the files belong to.
-		// Removing file IRs also removes the variant the files belong to.
-		// When removing file IRs, have the option to write back to the DB.
-		int  AddFileIRs(db_id_t variant_id);
-		int  RemoveFileIRs(db_id_t variant_id, bool write_to_DB);
-			
-		// get a variant
-		std::shared_ptr<VariantID_t> GetVariant(db_id_t variant_id);
-		// get file IRs (returns a shared ptr to a set of shared ptrs to file IRs)
-		std::shared_ptr<std::set<std::shared_ptr<FileIR_t>>> GetFileIRs(db_id_t variant_id);
-
-		// Write back all variants and file IRs stored in this IRFiles_t object.
-		int WriteBackAll(void);
-		
-	private:
-		// maps for speed of finding needed file IRs and/or variants
-		// that have already been read from the DB
-		std::map<db_id_t, std::shared_ptr<VariantID_t>> variant_map;
-		std::map<db_id_t, std::shared_ptr<std::set<std::shared_ptr<FileIR_t>>>> file_IRs_map;	
-
-};
-
-#endif
diff --git a/libIRDB/src/util/IRDB_Objects.cpp b/libIRDB/src/util/IRDB_Objects.cpp
new file mode 100644
index 000000000..fccb82458
--- /dev/null
+++ b/libIRDB/src/util/IRDB_Objects.cpp
@@ -0,0 +1,275 @@
+#include <map>
+#include <libIRDB-core.hpp>
+#include <libIRDB-util.hpp>
+#include <utils.hpp>
+#include <utility>
+#include <memory>
+#include <assert.h>
+
+
+using namespace libIRDB;
+using namespace std;
+
+
+IRDBObjects_t::~IRDBObjects_t()
+{
+        // All dynamically allocated members (DB objects)
+        // are held as shared pointers and don't need to be 
+        // explicitly deleted.
+}
+
+
+int IRDBObjects_t::AddFileIR(db_id_t variant_id, db_id_t file_id)
+{
+        map<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>>::iterator 
+            it = file_IR_map.find(file_id);
+        
+        if(it == file_IR_map.end())
+        {
+            return 1;
+        }
+        else
+        {            
+            if(it->second.second == NULL)
+            {
+                File_t* the_file = (it->second.first).get(); 
+                assert(the_file != NULL);
+            
+                assert(variant_map.find(variant_id) != variant_map.end());
+                VariantID_t& the_variant = *(variant_map.at(variant_id).get());
+                
+                it->second.second = make_shared<FileIR_t>(the_variant, the_file);
+                assert(it->second.second != NULL);
+            }
+            return 0;
+        }
+}
+
+
+int IRDBObjects_t::DeleteFileIR(db_id_t file_id, bool write_to_DB)
+{
+        int ret_status = 0;
+    
+        map<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>>::iterator 
+            it = file_IR_map.find(file_id);
+        
+        if(it == file_IR_map.end())
+        {
+            ret_status = 1;
+        }
+        else
+        {
+            if(it->second.second != NULL)
+            {
+                assert(it->second.second.unique());
+                
+                if(write_to_DB)
+                {
+                    shared_ptr<File_t> the_file = it->second.first;
+                    assert(the_file != NULL);
+                    
+                    try
+                    {
+                        cout<<"Writing changes for "<<the_file->GetURL()<<endl;
+                        (it->second.second)->WriteToDB();
+                    }
+                    catch (DatabaseError_t pnide)
+                    {
+                        cerr << "Unexpected database error: " << pnide << "file url: " << the_file->GetURL() << endl;
+                        ret_status = 2;
+                    }
+                    catch (...)
+                    {
+                        cerr << "Unexpected error file url: " << the_file->GetURL() << endl;
+                        ret_status = 2;
+                    }
+                }
+                (it->second.second).reset();
+            }
+        }       
+        
+        return ret_status;
+}
+
+
+int IRDBObjects_t::AddVariant(db_id_t variant_id)
+{
+        shared_ptr<VariantID_t> the_variant = make_shared<VariantID_t>(variant_id);        
+        assert(the_variant->IsRegistered()==true);
+        
+        pair<db_id_t, shared_ptr<VariantID_t>> var_pair = make_pair(variant_id, the_variant);
+        variant_map.insert(var_pair);
+        
+        // add files
+        for(set<File_t*>::iterator it=the_variant->GetFiles().begin();
+            it!=the_variant->GetFiles().end();
+            ++it
+           )
+        {            
+            shared_ptr<File_t> curr_file(*it);
+            shared_ptr<FileIR_t> curr_file_IR;
+                    
+            pair<shared_ptr<File_t>, shared_ptr<FileIR_t>> file_IR_pair = make_pair(curr_file, curr_file_IR);
+            pair<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>> file_map_pair = make_pair((*it)->GetBaseID(), file_IR_pair);
+            
+            file_IR_map.insert(file_map_pair);
+        }
+        
+        return 0;
+}
+
+
+int IRDBObjects_t::DeleteVariant(db_id_t variant_id, bool write_to_DB)
+{
+        int ret_status = 0;
+        map<db_id_t, shared_ptr<VariantID_t>>::iterator var_it = variant_map.find(variant_id);
+        
+        if(var_it == variant_map.end())
+        {
+            ret_status = 1;
+        }
+        else
+        {
+            bool files_being_shared = false;
+            for(set<File_t*>::iterator file_it=var_it->second->GetFiles().begin();
+                file_it!=var_it->second->GetFiles().end();
+                ++file_it
+               )
+            {
+                assert(file_IR_map.find((*file_it)->GetBaseID()) != file_IR_map.end());
+                pair<shared_ptr<File_t>, shared_ptr<FileIR_t>> file_IR_pair = file_IR_map.at((*file_it)->GetBaseID());
+                if(!file_IR_pair.first.unique() || !file_IR_pair.second.unique())
+                {
+                    files_being_shared = true;
+                }
+            }
+            
+            assert(!files_being_shared);
+            assert(var_it->second.unique());
+            
+            if(write_to_DB)
+            {
+                try
+                {
+                    cout<<"Writing changes for variant "<<variant_id<<endl;
+                    var_it->second->WriteToDB();
+                }
+                catch (DatabaseError_t pnide)
+                {
+                    cerr << "Unexpected database error: " << pnide << "variant ID: " << variant_id << endl;
+                    ret_status = 2;
+                }
+                catch (...)
+                {
+                    cerr << "Unexpected error variant ID: " << variant_id << endl;
+                    ret_status = 2;
+                }
+            }
+            // remove files and file IRs
+            for(set<File_t*>::iterator file_it2=var_it->second->GetFiles().begin();
+                file_it2!=var_it->second->GetFiles().end();
+                ++file_it2
+               )
+            {
+                file_IR_map.erase((*file_it2)->GetBaseID());
+            }
+            
+            // remove variant
+            variant_map.erase(variant_id);
+        }
+        
+        return ret_status;
+}
+
+
+bool IRDBObjects_t::WriteBackAll(void)
+{
+        bool all_successes = true;
+    
+        // Write back FileIRs
+        for(map<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>>::iterator
+                it = file_IR_map.begin(); 
+                it != file_IR_map.end();
+                ++it 
+            )
+        {
+            int result = IRDBObjects_t::DeleteFileIR((it->second.first)->GetBaseID(), true);
+            if(result != 0)
+            {
+                all_successes = false;
+            }
+        }
+    
+        // Write back Variants
+        for(map<db_id_t, shared_ptr<VariantID_t>>::iterator
+                it2 = variant_map.begin(); 
+                it2 != variant_map.end();
+                ++it2
+            )
+        {
+            int result = IRDBObjects_t::DeleteVariant((it2->second)->GetBaseID(), true);
+            if(result != 0)
+            {
+                all_successes = false;
+            }
+        }
+        
+        return all_successes;
+}
+
+
+shared_ptr<VariantID_t> IRDBObjects_t::GetVariant(db_id_t variant_id)
+{
+        map<db_id_t, shared_ptr<VariantID_t>>::iterator it = variant_map.find(variant_id);
+        
+        if(it == variant_map.end())
+        {
+            shared_ptr<VariantID_t> null_var;
+            return null_var;
+        }
+        else
+        {
+            return it->second;
+        }
+}
+
+
+shared_ptr<FileIR_t> IRDBObjects_t::GetFileIR(db_id_t file_id)
+{
+        map<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>>::iterator 
+            it = file_IR_map.find(file_id);
+        
+        if(it == file_IR_map.end())
+        {
+            shared_ptr<FileIR_t> null_fileIR;
+            return null_fileIR;
+        }
+        else
+        {
+            return it->second.second;
+        }
+}
+
+
+shared_ptr<File_t> IRDBObjects_t::GetFile(db_id_t file_id)
+{
+        map<db_id_t, pair<shared_ptr<File_t>, shared_ptr<FileIR_t>>>::iterator 
+            it = file_IR_map.find(file_id);
+        
+        if(it == file_IR_map.end())
+        {
+            shared_ptr<File_t> null_file;
+            return null_file;
+        }
+        else
+        {
+            return it->second.first;
+        }
+}
+
+
+pqxxDB_t* IRDBObjects_t::GetDBInterface()
+{
+        return &pqxx_interface;
+}
+
diff --git a/libIRDB/src/util/IR_Files.cpp b/libIRDB/src/util/IR_Files.cpp
deleted file mode 100644
index 1a51f0bcc..000000000
--- a/libIRDB/src/util/IR_Files.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <map>
-#include <libIRDB-core.hpp>
-#include <libIRDB-util.hpp>
-#include <utils.hpp>
-#include <utility>
-#include <memory>
-#include <iterator>
-
-
-using namespace libIRDB;
-using namespace std;
-
-
-IRFiles_t::~IRFiles_t()
-{
-	file_IR_map.clear(); // doesn't write back to DB
-}
-
-
-void IRFiles_t::AddFileIR(FileIR_t& IR_ref)
-{
-	File_t* file_ptr = IR_ref.GetFile();
-
-	assert(file_ptr);
-
-	file_IR_map.insert(pair<File_t*, shared_ptr<FileIR_t>>(file_ptr, shared_ptr<FileIR_t>(&IR_ref)));
-}
-
-
-// may throw a database error exception if writing back to DB.
-// If the write back fails, the FileIR will not be destroyed.
-void IRFiles_t::RemoveFileIR(FileIR_t& IR_ref, bool write_to_DB)
-{
-	if(!HasFileIR(IR_ref))
-		return;
-
-	if(write_to_DB)
-		IR_ref.WriteToDB();
-
-	File_t* file_ptr = IR_ref.GetFile();
-
-	assert(file_ptr);
-
-	file_IR_map.erase(file_ptr);	
-}
-
-
-// may throw a database error exception if writing back to DB.
-// If the write back fails, the FileIR will not be destroyed.
-void IRFiles_t::RemoveFileIR(File_t& file_ref, bool write_to_DB)
-{
-	if(!HasFileIR(file_ref))
-                return;
-
-        if(write_to_DB)
-                GetFileIR(file_ref)->WriteToDB();
-
-        file_IR_map.erase(&file_ref);
-}
-
-
-bool IRFiles_t::HasFileIR(File_t& file_ref)
-{
-	map<File_t*, shared_ptr<FileIR_t>>::iterator got = file_IR_map.find(&file_ref);
-
-  	if(got == file_IR_map.end())
-		return false;
-	else
-		return true;
-}
-
-
-bool IRFiles_t::HasFileIR(FileIR_t& IR_ref)
-{
-	File_t* file_ptr = IR_ref.GetFile();
-
-	assert(file_ptr);	
-
-	map<File_t*, shared_ptr<FileIR_t>>::iterator got = file_IR_map.find(file_ptr);
-
-        if(got == file_IR_map.end())
-                return false;
-        else
-                return true;
-}
-
-
-FileIR_t* IRFiles_t::GetFileIR(File_t& file_ref)
-{
-	map<File_t*, shared_ptr<FileIR_t>>::iterator got = file_IR_map.find(&file_ref);
-
-        if(got == file_IR_map.end())
-                return NULL;
-        else
-                return (got->second).get();		
-}
-
diff --git a/libIRDB/src/util/SConscript b/libIRDB/src/util/SConscript
index 6c9385cf2..673d28ffa 100644
--- a/libIRDB/src/util/SConscript
+++ b/libIRDB/src/util/SConscript
@@ -10,7 +10,7 @@ files=  '''
 	insn_preds.cpp
         IBT_Provenance.cpp
 	params.cpp
-	IR_Files.cpp
+	IRDB_Objects.cpp
 	'''
 cpppath=''' 
 	$SECURITY_TRANSFORMS_HOME/include/
-- 
GitLab