source: gsdl/trunk/packages/isis-gdl/CacheMan.cpp@ 14171

Last change on this file since 14171 was 6127, checked in by mdewsnip, 20 years ago

IsisGdl package for reading CDS/ISIS databases. Provided by Jean-Claude Dauphin at UNESCO, and modified slightly to compile and run under Linux.

  • Property svn:keywords set to Author Date Id Revision
File size: 5.0 KB
Line 
1/**********************************************************************
2 *
3 * CacheMan.cpp
4 * Copyright (C) 2003 UNESCO
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26
27#include "stdafx.h"
28#include "File.h"
29
30#include "CacheMan.h"
31
32
33CacheManager::CacheManager()
34{
35 maxblocks_ = 0;
36}
37CacheManager::CacheManager(unsigned blocksz, unsigned mxblks)
38{
39 PRECONDITION(maxblocks_ == 0);
40 maxblocks_ = mxblks;
41 nused_ = 0;
42 blocksize_ = blocksz;
43 buff_ = new char[blocksize_*maxblocks_];
44 diskAddrs_ = new FileSystem::FAU_t[maxblocks_];
45 useCounts_ = new unsigned[maxblocks_];
46 theFile_ = NULL;
47}
48/*
49 * Construct a cache manager for blocks of size blocksz and mxblks buffers
50 */
51void CacheManager::Create(unsigned blocksz, unsigned mxblks)
52{
53 PRECONDITION(maxblocks_ == 0);
54 maxblocks_ = mxblks;
55 nused_ = 0;
56 blocksize_ = blocksz;
57 buff_ = new char[blocksize_*maxblocks_];
58 diskAddrs_ = new FileSystem::FAU_t[maxblocks_];
59 useCounts_ = new unsigned[maxblocks_];
60 theFile_ = NULL;
61}
62
63//
64// Connect to a CFileBase
65//
66void CacheManager::Connect(CFileBase* file)
67{
68 PRECONDITION(nused_ == 0);
69 theFile_ = file;
70}
71//
72// Disconnect the cache from the CFileBase
73//
74void CacheManager::Disconnect()
75{
76 if (theFile_)
77 {
78 if (theFile_->IsOpen())
79 Flush();
80 }
81 theFile_ = NULL;
82}
83
84void CacheManager::Erase()
85{
86 Disconnect();
87 delete[] useCounts_;
88 delete[] diskAddrs_;
89 delete[] buff_;
90 maxblocks_ = 0;
91}
92
93
94CacheManager::~CacheManager()
95{
96 Disconnect();
97 delete[] useCounts_;
98 delete[] diskAddrs_;
99 delete[] buff_;
100}
101
102bool CacheManager::Flush()
103{
104 PRECONDITION(theFile_ != NULL && theFile_->IsOpen());
105 // Because we use "write through", this is all that's necessary:
106 if (theFile_->Flush() == FILE_NO_ERROR)
107 return true;
108 return false;
109}
110
111void CacheManager::Invalidate()
112{
113 nused_ = 0;
114}
115
116bool CacheManager::Read(FileSystem::FAU_t locn, void* dat)
117{
118 PRECONDITION(dat != NULL);
119 size_t islot = AgeAndFindSlot(locn);
120
121 if (islot == INVALID_NPOS)
122 {
123 // Not in buffer; we'll have to read it in from disk.
124 // Get a free slot.
125 if ((islot = GetFreeSlot()) == INVALID_NPOS)
126 return false;
127 diskAddrs_[islot] = locn;
128 if (!(theFile_->SeekTo(locn) == locn) ||
129 !(theFile_->Fetch(buff_ + islot*blocksize_, blocksize_) == FILE_NO_ERROR))
130 return false;
131 }
132 useCounts_[islot] = 0;
133 memcpy(dat, buff_ + islot*blocksize_, blocksize_);
134 return true;
135}
136
137bool CacheManager::Write(FileSystem::FAU_t locn, void* dat)
138{
139 PRECONDITION(dat != NULL);
140 PRECONDITION(theFile_->ReadyForWriting());
141 size_t islot = AgeAndFindSlot(locn);
142
143 if (islot == INVALID_NPOS)
144 {
145 // Not in buffer; find a free slot.
146 if ((islot = GetFreeSlot()) == INVALID_NPOS)
147 return false;
148 diskAddrs_[islot] = locn;
149 }
150
151 useCounts_[islot] = 0;
152 memcpy(buff_ + islot*blocksize_, dat, blocksize_);
153 if ((theFile_->SeekTo(locn) == locn) &&
154 (theFile_->Store(buff_ + islot*blocksize_, blocksize_) == FILE_NO_ERROR))
155 return true;
156 return false;
157}
158
159//////////////////////////////////////////////////////////////////////////////////
160// Private helper functions
161
162size_t CacheManager::AgeAndFindSlot(FileSystem::FAU_t locn)
163{
164 size_t islot = INVALID_NPOS;
165 for (register unsigned i = 0; i < nused_; i++)
166 {
167 if (diskAddrs_[i] == locn)
168 islot = i;
169 useCounts_[i]++; // Age the blocks
170 }
171 return islot;
172}
173
174bool CacheManager::Flush(unsigned)
175{
176 if (theFile_->Flush() == FILE_NO_ERROR)
177 return true;
178 return false;
179}
180
181size_t CacheManager::GetFreeSlot()
182{
183 size_t islot;
184
185 if (nused_ < maxblocks_)
186 {
187 islot = nused_++; // Found an unused slot.
188 }
189 else
190 {
191 // No free slots; get the Least Recently Used block
192 islot = LRU();
193
194 if (theFile_->ReadyForWriting())
195 if (!Flush(islot))
196 islot = INVALID_NPOS;
197 }
198 return islot;
199}
200
201size_t CacheManager::LRU() const
202{
203 size_t islot = 0;
204 unsigned maxCount = useCounts_[0];
205 for (register unsigned i = 1; i < nused_; i++)
206 {
207 if (useCounts_[i] > maxCount)
208 {
209 maxCount = useCounts_[islot = i];
210 }
211 }
212 return islot;
213}
Note: See TracBrowser for help on using the repository browser.