ITANUPCUFilterPool.cpp 5.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
#include "ITANUPCUFilterPool.h"
#include "ITANUPCUFilter.h"

#include <ITADebug.h>
#include <ITAException.h>
#include <ITAFunctors.h>

#include <algorithm>
#include <cassert>
#include <cstdio>

// Debug-Meldung ausgeben
#define UFILTERPOOL_VERBOSE 1

// Zugehrigskeits-Test bei release()
#define UFILTERPOOL_CHECK_OWNERSHIP 1

UFilterPool::UFilterPool(const CUPartition* pPartition, int iInitialSize)
: m_pPartition(pPartition)
{
	assert( pPartition );
	assert( iInitialSize >= 0 );

	Grow(iInitialSize);
}

UFilterPool::~UFilterPool() {
	ITACriticalSectionLock oLock(m_csFilters);

	std::for_each(m_lpFreeFilters.begin(), m_lpFreeFilters.end(), deleteFunctor<CUFilter>);
	std::for_each(m_lpUsedFilters.begin(), m_lpUsedFilters.end(), deleteFunctor<CUFilter>);
	std::for_each(m_lpAutoFilters.begin(), m_lpAutoFilters.end(), deleteFunctor<CUFilter>);
}

int UFilterPool::GetNumFreeFilters() const {
	ITACriticalSectionLock oLock(m_csFilters);
	return (int) m_lpFreeFilters.size();
}

int UFilterPool::GetNumUsedFilters() const {
	ITACriticalSectionLock oLock(m_csFilters);
	return (int) m_lpUsedFilters.size() + (int) m_lpAutoFilters.size();
}

int UFilterPool::GetNumTotalFilters() const {
	ITACriticalSectionLock oLock(m_csFilters);
	return (int) m_lpFreeFilters.size() + (int) m_lpUsedFilters.size() + (int) m_lpAutoFilters.size();
}

void UFilterPool::Grow(int iDelta) {
	ITACriticalSectionLock oLock(m_csFilters);

	for (int i=0; i<iDelta; i++)
		m_lpFreeFilters.push_back( CreateFilter() );
}

CUFilter* UFilterPool::RequestFilter() {
	ITACriticalSectionLock oLock(m_csFilters);

	CUFilter* pFilter(nullptr);

	if (m_lpFreeFilters.empty()) {
		// Fall: Keine Filter in der Frei-Liste -> Zunchst schauen ob freie Filter in der Auto-Liste
		if (!m_lpAutoFilters.empty()) {
			for (std::list<CUFilter*>::iterator it=m_lpAutoFilters.begin(); it!=m_lpAutoFilters.end(); ++it) {
				/*
				 *  Wichtig: Wenn der Filter bereits in der Auto-Liste ist,
				 *           hat der Benutzer fr dieses Filter release() aufgerufen.
				 *           Er braucht den Filter also nicht mehr und darf den
				 *           ihm zuvor genannten Zeiger nicht mehr weiterbenutzen.
				 *           Deshalb kann auch den Filter auch nicht zwischenzeitlich
				 *           in einen anderen Falter einsetzen.
				 *
				 *           Fazit: Es ist sicher hier nur-lesend zu testen!
				 */

				assert( (*it) != 0 );

				if (!(*it)->IsInUse()) {
					pFilter = (*it);

					// Filter wieder vergeben
					m_lpAutoFilters.erase(it);
#if (UFILTERPOOL_VERBOSE==1)
					DEBUG_PRINTF("[UFilterPool] Reusing auto filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
						         pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif
					break;
				}
//				} else {
//					// Nur Meldung machen
//					UFilter::State::StateStruct ss;
//					ss.iPrepRefCount = 0;
//					ss.iUseRefCount = 0;
//					if (pFilter) atomic_read32( &pFilter->m_oState.m_oState, &ss );
//#if (UFILTERPOOL_VERBOSE==1)
//					DEBUG_PRINTF("[UFilterPool] Cannot reusing auto filter 0x%08Xh (preps=%d, uses=%d) [Used %d, Auto %d, Free %d, Total %d]\n",
//						pFilter, ss.iPrepRefCount, ss.iUseRefCount, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), getNumTotalFilters());
//#endif
//				}
			}
		}

		if (!pFilter) {
			// Fall: Auch kein freies Filter in der Auto-Liste -> Neues Filter erzeugen
			pFilter = CreateFilter();
		}

		m_lpUsedFilters.push_back(pFilter);

	} else {
		// Fall: Freie Filter verfgbar
		pFilter = m_lpFreeFilters.back();
		m_lpFreeFilters.pop_back();
		m_lpUsedFilters.push_back(pFilter);
	}

#if (UFILTERPOOL_VERBOSE==1)
	DEBUG_PRINTF("[UFilterPool] Request returns filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
			     pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif

	return pFilter;
}

void UFilterPool::ReleaseFilter(CUFilter* pFilter) {
	// TODO: Release muss ohne Lock auskommen!
	// Sonst haben wir Blocking-Artefakte im Stream-Processing
	ITACriticalSectionLock oLock(m_csFilters);

	assert( pFilter );

#if (UFILTERPOOL_VERBOSE==1)
		DEBUG_PRINTF("[UFilterPool] Release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
			   pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif

#if (UFILTERPOOL_CHECK_OWNERSHIP==1)
	assert( pFilter->m_pParentPool == this );
	if (pFilter->m_pParentPool != this)
		ITA_EXCEPT1(UNKNOWN, "Internal error E2331");

	std::list<CUFilter*>::iterator it = std::find(m_lpUsedFilters.begin(), m_lpUsedFilters.end(), pFilter);
	assert( it != m_lpUsedFilters.end() );
	if (it == m_lpUsedFilters.end())
		ITA_EXCEPT1(UNKNOWN, "Internal error E2332");
#endif
	
	if (pFilter->IsInUse()) {
		// Ist der Filter bereits oder noch in Benutzung
		// -> Zur Freigabe vormerken (Auto-Liste)
		m_lpUsedFilters.erase(it);
		m_lpAutoFilters.push_back(pFilter);

#if (UFILTERPOOL_VERBOSE==1)
		DEBUG_PRINTF("[UFilterPool] Auto-release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
			         pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif
		return;
	}

	// Filter wieder in die Frei-Liste
	m_lpUsedFilters.erase(it);
	m_lpFreeFilters.push_back(pFilter);

#if (UFILTERPOOL_VERBOSE==1)
	DEBUG_PRINTF("[UFilterPool] Instant-release filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
		         pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif
}

CUFilter* UFilterPool::CreateFilter() {
	CUFilter* pFilter = new CUFilter(m_pPartition, this);

#if (UFILTERPOOL_VERBOSE==1)
	DEBUG_PRINTF("[UFilterPool] Created new filter 0x%08Xh [Used %d, Auto %d, Free %d, Total %d]\n",
		         pFilter, m_lpUsedFilters.size(), m_lpAutoFilters.size(), m_lpFreeFilters.size(), GetNumTotalFilters());
#endif

	return pFilter;
}