1 /*
2    Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
3     All rights reserved. Use is subject to license terms.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License, version 2.0,
7    as published by the Free Software Foundation.
8 
9    This program is also distributed with certain software (including
10    but not limited to OpenSSL) that is licensed under separate terms,
11    as designated in a particular file or component or in included license
12    documentation.  The authors of MySQL hereby grant you an additional
13    permission to link the program and your derivative works with the
14    separately licensed software that they have included with MySQL.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License, version 2.0, for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 */
25 
26 #ifndef NDB_OBJECT_ID_MAP_HPP
27 #define NDB_OBJECT_ID_MAP_HPP
28 
29 #include <ndb_global.h>
30 #include <NdbOut.hpp>
31 
32 #include <EventLogger.hpp>
33 extern EventLogger * g_eventLogger;
34 
35 //#define DEBUG_OBJECTMAP
36 
37 /**
38   * Global ObjectMap
39   */
40 class NdbObjectIdMap
41 {
42 public:
43   STATIC_CONST( InvalidId = 0x7fffffff );
44   NdbObjectIdMap(Uint32 initalSize, Uint32 expandSize);
45   ~NdbObjectIdMap();
46 
47   Uint32 map(void * object);
48   void * unmap(Uint32 id, void *object);
49 
50   void * getObject(Uint32 id);
51 private:
52   const Uint32 m_expandSize;
53   Uint32 m_size;
54   Uint32 m_firstFree;
55   /**
56    * We put released entries at the end of the free list. That way, we delay
57    * re-use of an object id as long as possible. This minimizes the chance
58    * of sending an incoming message to the wrong object because the recipient
59    * object id was reused.
60    */
61   Uint32 m_lastFree;
62 
63   class MapEntry
64   {
65   public:
isFree() const66     bool isFree() const
67     {
68       return (m_val & 1) == 1;
69     }
70 
getNext() const71     Uint32 getNext() const
72     {
73       assert(isFree());
74       return static_cast<Uint32>(m_val >> 1);
75     }
76 
setNext(Uint32 next)77     void setNext(Uint32 next)
78     {
79       m_val = (next << 1) | 1;
80     }
81 
getObj() const82     void* getObj() const
83     {
84       assert((m_val & 3) == 0);
85       return reinterpret_cast<void*>(m_val);
86     }
87 
setObj(void * obj)88     void setObj(void* obj)
89     {
90       m_val = reinterpret_cast<UintPtr>(obj);
91       assert((m_val & 3) == 0);
92     }
93 
94   private:
95     /**
96      * This holds either a pointer to a mapped object *or* the index of the
97      * next entry in the free list. If it is a pointer, then the two least
98      * significant bits should be zero (requiring all mapped objects to be
99      * four-byte aligned). If it is an index, then bit 0 should be set.
100      */
101     UintPtr m_val;
102   };
103 
104   MapEntry* m_map;
105 
106   int expand(Uint32 newSize);
107   // For debugging purposes.
108   bool checkConsistency();
109 };
110 
111 inline
112 Uint32
map(void * object)113 NdbObjectIdMap::map(void * object)
114 {
115   if(m_firstFree == InvalidId && expand(m_expandSize))
116     return InvalidId;
117 
118   const Uint32 ff = m_firstFree;
119   m_firstFree = m_map[ff].getNext();
120   m_map[ff].setObj(object);
121 
122   DBUG_PRINT("info",("NdbObjectIdMap::map(0x%lx) %u", (long) object, ff<<2));
123 
124   return ff<<2;
125 }
126 
127 inline
128 void *
unmap(Uint32 id,void * object)129 NdbObjectIdMap::unmap(Uint32 id, void *object)
130 {
131   const Uint32 i = id>>2;
132 
133   assert(i < m_size);
134   if(i < m_size)
135   {
136     void * const obj = m_map[i].getObj();
137     if (object == obj)
138     {
139       m_map[i].setNext(InvalidId);
140       if (m_firstFree == InvalidId)
141       {
142         m_firstFree = i;
143       }
144       else
145       {
146         m_map[m_lastFree].setNext(i);
147       }
148       m_lastFree = i;
149     }
150     else
151     {
152       g_eventLogger->error("NdbObjectIdMap::unmap(%u, 0x%lx) obj=0x%lx",
153                            id, (long) object, (long) obj);
154       DBUG_PRINT("error",("NdbObjectIdMap::unmap(%u, 0x%lx) obj=0x%lx",
155                           id, (long) object, (long) obj));
156       assert(false);
157       return 0;
158     }
159 
160     DBUG_PRINT("info",("NdbObjectIdMap::unmap(%u) obj=0x%lx", id, (long) obj));
161 
162     return obj;
163   }
164   return 0;
165 }
166 
167 inline void *
getObject(Uint32 id)168 NdbObjectIdMap::getObject(Uint32 id)
169 {
170   // DBUG_PRINT("info",("NdbObjectIdMap::getObject(%u) obj=0x%x", id,  m_map[id>>2].m_obj));
171   id >>= 2;
172   assert(id < m_size);
173   if(id < m_size)
174   {
175     if(m_map[id].isFree())
176     {
177       return 0;
178     }
179     else
180     {
181       return m_map[id].getObj();
182     }
183   }
184   return 0;
185 }
186 #endif
187