tdbPCache.c 6.7 KB
Newer Older
H
refact  
Hongze Cheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
H
Hongze Cheng 已提交
15 16
#include "tdbInt.h"

H
more  
Hongze Cheng 已提交
17
struct SPCache {
H
Hongze Cheng 已提交
18 19 20
  int         pageSize;
  int         cacheSize;
  tdb_mutex_t mutex;
H
Hongze Cheng 已提交
21
  SPage      *pList;
H
Hongze Cheng 已提交
22 23 24 25 26 27 28
  int         nFree;
  SPage      *pFree;
  int         nPage;
  int         nHash;
  SPage     **pgHash;
  int         nRecyclable;
  SPage       lru;
H
Hongze Cheng 已提交
29 30
};

H
more  
Hongze Cheng 已提交
31 32 33 34 35 36
#define PCACHE_PAGE_HASH(pPgid)                              \
  ({                                                         \
    u32 *t = (u32 *)((pPgid)->fileid);                       \
    t[0] + t[1] + t[2] + t[3] + t[4] + t[5] + (pPgid)->pgno; \
  })
#define PAGE_IS_PINNED(pPage) ((pPage)->pLruNext == NULL)
H
Hongze Cheng 已提交
37

H
refact  
Hongze Cheng 已提交
38
static int    tdbPCacheOpenImpl(SPCache *pCache);
H
refact  
Hongze Cheng 已提交
39
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid);
H
Hongze Cheng 已提交
40 41 42 43
static void   tdbPCachePinPage(SPCache *pCache, SPage *pPage);
static void   tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage);
static void   tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage);
static void   tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage);
H
Hongze Cheng 已提交
44 45 46 47 48 49
static int    tdbPCacheCloseImpl(SPCache *pCache);

static void tdbPCacheInitLock(SPCache *pCache) { tdbMutexInit(&(pCache->mutex), NULL); }
static void tdbPCacheDestroyLock(SPCache *pCache) { tdbMutexDestroy(&(pCache->mutex)); }
static void tdbPCacheLock(SPCache *pCache) { tdbMutexLock(&(pCache->mutex)); }
static void tdbPCacheUnlock(SPCache *pCache) { tdbMutexUnlock(&(pCache->mutex)); }
H
Hongze Cheng 已提交
50

H
Hongze Cheng 已提交
51
int tdbPCacheOpen(int pageSize, int cacheSize, SPCache **ppCache) {
H
more  
Hongze Cheng 已提交
52
  SPCache *pCache;
H
Hongze Cheng 已提交
53 54
  void    *pPtr;
  SPage   *pPgHdr;
H
Hongze Cheng 已提交
55

H
Hongze Cheng 已提交
56
  pCache = (SPCache *)tdbOsCalloc(1, sizeof(*pCache));
H
more  
Hongze Cheng 已提交
57
  if (pCache == NULL) {
H
Hongze Cheng 已提交
58 59 60
    return -1;
  }

H
more  
Hongze Cheng 已提交
61 62
  pCache->pageSize = pageSize;
  pCache->cacheSize = cacheSize;
H
Hongze Cheng 已提交
63

H
more  
Hongze Cheng 已提交
64
  if (tdbPCacheOpenImpl(pCache) < 0) {
H
Hongze Cheng 已提交
65
    tdbOsFree(pCache);
H
more  
Hongze Cheng 已提交
66
    return -1;
H
Hongze Cheng 已提交
67 68
  }

H
more  
Hongze Cheng 已提交
69
  *ppCache = pCache;
H
Hongze Cheng 已提交
70 71 72
  return 0;
}

H
Hongze Cheng 已提交
73
int tdbPCacheClose(SPCache *pCache) {
H
Hongze Cheng 已提交
74 75 76 77
  if (pCache) {
    tdbPCacheCloseImpl(pCache);
    tdbOsFree(pCache);
  }
H
Hongze Cheng 已提交
78
  return 0;
H
Hongze Cheng 已提交
79 80
}

H
refact  
Hongze Cheng 已提交
81
SPage *tdbPCacheFetch(SPCache *pCache, const SPgid *pPgid) {
H
refact  
Hongze Cheng 已提交
82
  SPage *pPage;
H
more  
Hongze Cheng 已提交
83

H
Hongze Cheng 已提交
84
  tdbPCacheLock(pCache);
H
Hongze Cheng 已提交
85

H
refact  
Hongze Cheng 已提交
86
  pPage = tdbPCacheFetchImpl(pCache, pPgid);
H
Hongze Cheng 已提交
87 88 89 90
  if (pPage) {
    TDB_REF_PAGE(pPage);
  }

H
Hongze Cheng 已提交
91
  tdbPCacheUnlock(pCache);
H
more  
Hongze Cheng 已提交
92 93

  return pPage;
H
Hongze Cheng 已提交
94 95
}

H
Hongze Cheng 已提交
96
void tdbPCacheRelease(SPCache *pCache, SPage *pPage) {
H
Hongze Cheng 已提交
97 98 99 100 101 102
  i32 nRef;

  nRef = TDB_UNREF_PAGE(pPage);
  ASSERT(nRef >= 0);

  if (nRef == 0) {
H
Hongze Cheng 已提交
103
    tdbPCacheUnpinPage(pCache, pPage);
H
more  
Hongze Cheng 已提交
104
  }
H
Hongze Cheng 已提交
105 106
}

H
Hongze Cheng 已提交
107
int tdbPCacheGetPageSize(SPCache *pCache) { return pCache->pageSize; }
H
more  
Hongze Cheng 已提交
108

H
refact  
Hongze Cheng 已提交
109
static SPage *tdbPCacheFetchImpl(SPCache *pCache, const SPgid *pPgid) {
H
refact  
Hongze Cheng 已提交
110
  SPage *pPage;
H
more  
Hongze Cheng 已提交
111 112 113 114

  // 1. Search the hash table
  pPage = pCache->pgHash[PCACHE_PAGE_HASH(pPgid) % pCache->nHash];
  while (pPage) {
H
more  
Hongze Cheng 已提交
115
    if (TDB_IS_SAME_PAGE(&(pPage->pgid), pPgid)) break;
H
more  
Hongze Cheng 已提交
116 117 118
    pPage = pPage->pHashNext;
  }

H
refact  
Hongze Cheng 已提交
119 120
  if (pPage) {
    tdbPCachePinPage(pCache, pPage);
H
more  
Hongze Cheng 已提交
121
  }
H
refact  
Hongze Cheng 已提交
122
  return pPage;
H
more  
Hongze Cheng 已提交
123

H
more  
Hongze Cheng 已提交
124 125 126 127 128 129 130 131 132 133 134
  // 2. Try to allocate a new page from the free list
  if (pCache->pFree) {
    pPage = pCache->pFree;
    pCache->pFree = pPage->pFreeNext;
    pCache->nFree--;
    pPage->pLruNext = NULL;
  }

  // 3. Try to Recycle a page
  if (!pPage && !pCache->lru.pLruPrev->isAnchor) {
    pPage = pCache->lru.pLruPrev;
H
Hongze Cheng 已提交
135 136
    tdbPCacheRemovePageFromHash(pCache, pPage);
    tdbPCachePinPage(pCache, pPage);
H
more  
Hongze Cheng 已提交
137 138
  }

H
more  
Hongze Cheng 已提交
139
  // 4. Try a stress allocation (TODO)
H
more  
Hongze Cheng 已提交
140 141 142 143 144

  // 5. Page here are just created from a free list
  // or by recycling or allocated streesly,
  // need to initialize it
  if (pPage) {
H
more  
Hongze Cheng 已提交
145
    memcpy(&(pPage->pgid), pPgid, sizeof(*pPgid));
H
more  
Hongze Cheng 已提交
146
    pPage->pLruNext = NULL;
H
more  
Hongze Cheng 已提交
147
    pPage->pPager = NULL;
H
Hongze Cheng 已提交
148
    tdbPCacheAddPageToHash(pCache, pPage);
H
more  
Hongze Cheng 已提交
149 150
  }

H
more  
Hongze Cheng 已提交
151
  return pPage;
H
more  
Hongze Cheng 已提交
152 153
}

H
Hongze Cheng 已提交
154
static void tdbPCachePinPage(SPCache *pCache, SPage *pPage) {
H
more  
Hongze Cheng 已提交
155 156 157 158 159 160
  if (!PAGE_IS_PINNED(pPage)) {
    pPage->pLruPrev->pLruNext = pPage->pLruNext;
    pPage->pLruNext->pLruPrev = pPage->pLruPrev;
    pPage->pLruNext = NULL;

    pCache->nRecyclable--;
H
more  
Hongze Cheng 已提交
161
  }
H
more  
Hongze Cheng 已提交
162 163
}

H
Hongze Cheng 已提交
164 165
static void tdbPCacheUnpinPage(SPCache *pCache, SPage *pPage) {
  i32 nRef;
H
Hongze Cheng 已提交
166 167 168

  tdbPCacheLock(pCache);

H
Hongze Cheng 已提交
169 170
  ASSERT(!pPage->isDirty);

H
Hongze Cheng 已提交
171
  nRef = TDB_GET_PAGE_REF(pPage);
H
Hongze Cheng 已提交
172 173 174 175
  ASSERT(nRef >= 0);
  if (nRef == 0) {
    // Add the page to LRU list
    ASSERT(pPage->pLruNext == NULL);
H
more  
Hongze Cheng 已提交
176

H
Hongze Cheng 已提交
177 178 179 180 181
    pPage->pLruPrev = &(pCache->lru);
    pPage->pLruNext = pCache->lru.pLruNext;
    pCache->lru.pLruNext->pLruPrev = pPage;
    pCache->lru.pLruNext = pPage;
  }
H
more  
Hongze Cheng 已提交
182 183

  pCache->nRecyclable++;
H
Hongze Cheng 已提交
184 185

  tdbPCacheUnlock(pCache);
H
more  
Hongze Cheng 已提交
186 187
}

H
Hongze Cheng 已提交
188 189 190
static void tdbPCacheRemovePageFromHash(SPCache *pCache, SPage *pPage) {
  SPage **ppPage;
  int     h;
H
more  
Hongze Cheng 已提交
191 192 193 194 195 196 197 198 199 200

  h = PCACHE_PAGE_HASH(&(pPage->pgid));
  for (ppPage = &(pCache->pgHash[h % pCache->nHash]); *ppPage != pPage; ppPage = &((*ppPage)->pHashNext))
    ;
  ASSERT(*ppPage == pPage);
  *ppPage = pPage->pHashNext;

  pCache->nPage--;
}

H
Hongze Cheng 已提交
201 202
static void tdbPCacheAddPageToHash(SPCache *pCache, SPage *pPage) {
  int h;
H
more  
Hongze Cheng 已提交
203

H
more  
Hongze Cheng 已提交
204
  h = PCACHE_PAGE_HASH(&(pPage->pgid)) % pCache->nHash;
H
more  
Hongze Cheng 已提交
205 206 207 208 209

  pPage->pHashNext = pCache->pgHash[h];
  pCache->pgHash[h] = pPage;

  pCache->nPage++;
H
more  
Hongze Cheng 已提交
210 211 212
}

static int tdbPCacheOpenImpl(SPCache *pCache) {
H
refact  
Hongze Cheng 已提交
213
  SPage *pPage;
H
Hongze Cheng 已提交
214
  u8    *pPtr;
H
refact  
Hongze Cheng 已提交
215
  int    tsize;
H
Hongze Cheng 已提交
216
  int    ret;
H
more  
Hongze Cheng 已提交
217 218 219 220 221 222 223

  tdbPCacheInitLock(pCache);

  // Open the free list
  pCache->nFree = 0;
  pCache->pFree = NULL;
  for (int i = 0; i < pCache->cacheSize; i++) {
H
Hongze Cheng 已提交
224
    ret = tdbPageCreate(pCache->pageSize, &pPage, NULL, NULL);
H
Hongze Cheng 已提交
225 226
    if (ret < 0) {
      // TODO: handle error
H
more  
Hongze Cheng 已提交
227 228 229 230 231 232
      return -1;
    }

    // pPage->pgid = 0;
    pPage->isAnchor = 0;
    pPage->isLocalPage = 1;
H
Hongze Cheng 已提交
233
    TDB_INIT_PAGE_REF(pPage);
H
more  
Hongze Cheng 已提交
234 235 236
    pPage->pHashNext = NULL;
    pPage->pLruNext = NULL;
    pPage->pLruPrev = NULL;
H
more  
Hongze Cheng 已提交
237
    pPage->pDirtyNext = NULL;
H
more  
Hongze Cheng 已提交
238 239 240 241 242 243 244 245 246

    pPage->pFreeNext = pCache->pFree;
    pCache->pFree = pPage;
    pCache->nFree++;
  }

  // Open the hash table
  pCache->nPage = 0;
  pCache->nHash = pCache->cacheSize;
H
Hongze Cheng 已提交
247
  pCache->pgHash = (SPage **)tdbOsCalloc(pCache->nHash, sizeof(SPage *));
H
more  
Hongze Cheng 已提交
248 249 250 251 252 253 254 255 256 257 258 259
  if (pCache->pgHash == NULL) {
    // TODO
    return -1;
  }

  // Open LRU list
  pCache->nRecyclable = 0;
  pCache->lru.isAnchor = 1;
  pCache->lru.pLruNext = &(pCache->lru);
  pCache->lru.pLruPrev = &(pCache->lru);

  return 0;
H
Hongze Cheng 已提交
260 261
}

H
Hongze Cheng 已提交
262 263 264 265 266
static int tdbPCacheCloseImpl(SPCache *pCache) {
  SPage *pPage;

  for (pPage = pCache->pList; pPage; pPage = pCache->pList) {
    pCache->pList = pPage->pCacheNext;
H
refact  
Hongze Cheng 已提交
267
    tdbPageDestroy(pPage, NULL, NULL);
H
Hongze Cheng 已提交
268 269 270 271
  }

  tdbPCacheDestroyLock(pCache);
}